userDatabase是一个由元组组成的列表,例如(id,username,password)。如何使用最大ID过滤列表?我现在所做的只是做了什么,但我认为我把它包含在某些背景下。
newUser :: UserDatabase -> UserDatabase
newUser usrdb = filter (\(usrid,_,_) -> usrid == (maximum [x | (x, _, _) <- userdb])) userdb
提前致谢!
答案 0 :(得分:3)
所有的usrid值都是不同的吗?在这种情况下,只有一个最大值,因此您可以执行以下操作:
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)
答案 1 :(得分:1)
未经测试,但应该让你去:
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
的第一个参数是一个从列表元素中提取比较字段的函数。答案 2 :(得分:0)
我有一个类型[(X, (R, R))]
的列表(元组列表,其中2 nd 元素也是一个元组),其中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
,您需要做的就是flip比较器,因为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
,但是这个双重工作?明确的递归?为什么不使用right fold实现相同的功能:
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
,因为它从小分类大):
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)]