繁体   English   中英

按最大元素过滤元组列表

[英]Filter list of tuples by maximum element

userDatabase是一个由元组(例如,(id,用户名,密码))组成的列表。 如何使用最大ID过滤列表? 目前我什么也没做,但我认为我在某些情况下也将其包括在内。

newUser :: UserDatabase -> UserDatabase
newUser usrdb = filter (\(usrid,_,_) -> usrid == (maximum [x | (x, _, _) <- userdb])) userdb

提前致谢!

所有的普遍价值都不同吗? 在这种情况下,只有一个最大值,因此您可以执行以下操作:

type User = (Int, String, String)
type UserDatabase = [User]

fst3 (x, _y, _z) = x

userHigh :: UserDatabase -> User
userHigh = maximumBy (comparing fst3)

如果ID不相同,则可能有一些联系,因此您需要返回一个列表

usersHigh :: UserDatabase -> [User]
usersHigh = concat . take 1
          . groupBy (on (==) fst3)
          . sortBy (flip $ comparing fst3)

未经测试,但应该可以帮助您:

maximumBy :: Ord b => (a -> b) -> [a] -> Maybe a
maximumBy extract [] = Nothing
maximumBy extract (x:xs) = go x xs
    where go candidate [] = Just candidate
          go candidate (x:xs)
              | extract x > extract candidate = go x xs
              | otherwise = go candidate xs

编辑:哦,bhelkir指出此函数已存在于库中。 无论如何,有几点:

  1. 如果您尝试从列表中仅获取一项,则它不是filter操作,而更像是findminimum / maximum操作。
  2. 您的使用方式如下所示: maximumBy (\\(usrid,_,_) -> usrid) users maximumBy的第一个参数是一个从列表的元素中提取比较字段的函数。

我有一个类型为[(X, (R, R))]的列表(一个元组的列表,其中第二个元素也是一个元组),其中XR是一些任意类型,而ROrd类型类的成员。 这样的列表的示例: [(0, (0,1)), (1, (1,1)), (2, (0,0)), (3, (1,0))] 想象一下,我想找到此列表的所有元素,其中第二个元素的第一个元素(即内部元组的左元素)最大。 但是我不想要一个这样的元素,而是想要所有元素,其中一个内部对的左元素最大。 因此,在上述列表中调用的我的函数应返回[(1, (1,1)), (3, (1,0))] maximumBy无效,因为它将仅返回一个元素。 因此,我编写了maximumBy的变体,该变体返回多个最大值:

maximumByM :: (a -> a -> Ordering) -> [a] -> [a]
maximumByM c (x:xs) = maximumByM' c xs [x]
  where maximumByM' _ [] acc = acc
        maximumByM' c (x:xs) acc@(a:_) = case x `c` a of
          LT -> maximumByM' c xs acc
          EQ -> maximumByM' c xs (x:acc)
          GT -> maximumByM' c xs [x]

后缀-M表示“多个”。 此多值函数返回所有最大值的列表(根据自定义比较):

maximumByM compare [1,2,3] -- [3]
maximumByM compare [1,2,3,1,2,3] -- [3,3]
maximumByM (comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(6,2),(6,1)]
maximumByM (comparing snd) [(5,1), (5,2), (6,1), (6,2)] -- [(6,2),(5,2)]

要实现minimumByM您需要做的就是翻转比较器,因为compare 1 2 == (flip compare) 2 1

maximumByM (flip $ comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(5,2),(5,1)]
-- the below 2 are equivalent due to Haskell's currying
minimumByM = maximumByM . flip
minimumByM c xs = maximumByM (flip c) xs

不幸的是, maximumByM以相反的顺序返回了列表。 我可以在代码中添加reverse符号,但是这种双重作用? 和显式递归? 为什么不使用右折叠实现相同的功能:

maximumByM :: (a -> a -> Ordering) -> [a] -> [a]
maximumByM _ [] = []
maximumByM c (x:xs) = foldr f [x] xs
  where f = (\e acc@(a:_) -> case c e a of
              LT -> acc
              EQ -> e:acc
              GT -> [e])

现在,它以与原始列表中找到的元素相同的顺序返回列表:

maximumByM (comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(6,1),(6,2)]

当然,您可以使用Boyd Stephen Smith Jr的方法,将groupBysortBy结合起来( sortBy需要flip因为它sortBy排序):

maximumByM :: (a -> a -> Ordering) -> [a] -> [a]
maximumByM _ [] = []
maximumByM c xs = head $ groupBy ((==EQ) .: c) $ sortBy (flip c) xs
  where (.:) = (.).(.) -- x .: y = \a b -> x(y a b)

您不需要反转列表,因为sortBy会保留它认为相等的元素顺序:

maximumByM (comparing fst) [(5,1), (5,2), (6,1), (6,2)] -- [(6,1),(6,2)]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM