[英]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指出此函数已存在于库中。 无论如何,有几点:
filter
操作,而更像是find
或minimum
/ maximum
操作。 maximumBy (\\(usrid,_,_) -> usrid) users
。 maximumBy
的第一个参数是一个从列表的元素中提取比较字段的函数。 我有一个类型为[(X, (R, R))]
的列表(一个元组的列表,其中第二个元素也是一个元组),其中X
和R
是一些任意类型,而R
是Ord
类型类的成员。 这样的列表的示例: [(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的方法,将groupBy
和sortBy
结合起来( 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.