如何找到列表中的所有最小元素?目前我有一个元组列表,例如:
[(10,'a'),(5,'b'),(1,'c'),(8,'d'),(1,'e')]
我希望你能够将列表中的所有最小元素放入一个新列表中进行输出。例如:
[(1,'c'),(1,'e')]
我尝试过
minimumBy (comparing fst) xs
但这只返回第一个最小元素。
在获取第一个值的最小值后,我们可以根据这些项筛选列表。因为您想要检索最小项的列表,所以我们可以通过返回空列表来处理空列表:
minimumsFst :: Ord a => [(a, b)] -> [(a, b)]
minimumsFst [] = []
minimumsFst xs = filter ((==) minfst . fst) xs
where minfst = minimum (map fst xs)
例如:
Prelude> minimumsFst [(10,'a'),(5,'b'),(1,'c'),(8,'d'),(1,'e')]
[(1,'c'),(1,'e')]
一句话总结,关键是排序。
Prelude Data.List> let a = [(1,'c'),(2,'b'),(1,'w')]
Prelude Data.List> (\xs@((m,_):_) -> takeWhile ((== m) . fst ) xs) . sortOn fst $ a
[(1,'c'),(1,'w')]
sortOn
能够在O(n lg n)的时间内产生最小值?(虽然,如果我花费超过两秒钟思考使用了哪种排序算法,我可能可以回答自己的问题...) - chepner{-# LANGUAGE ScopedTypeVariables #-}
import Data.Foldable (foldl')
minimumsBy :: forall a. (a -> a -> Ordering) -> [a] -> [a]
minimumsBy _ [] = []
minimumsBy f (x:xs) = postprocess $ foldl' go (x, id) xs
where
go :: (a, [a] -> [a]) -> a -> (a, [a] -> [a])
go acc@(x, xs) y = case f x y of
LT -> acc
EQ -> (x, xs . (y:))
GT -> (y, id)
postprocess :: (a, [a] -> [a]) -> [a]
postprocess (x, xs) = x:xs []
[a] -> [a]
类型被称为差异列表,也称为Hughes列表。你也可以通过 foldr
轻松地实现这个功能:
minimumsFst :: Ord a => [(a, b)] -> [(a, b)]
minimumsFst xs = go (minfst xs) xs
where
go mn ls = foldr (\(x, y) rs -> if (x == mn) then (x,y) : rs else rs) [] xs
minfst ls = minimum (map fst ls)
使用您的示例:
minimumsFst [(10,'a'),(5,'b'),(1,'c'),(8,'d'),(1,'e')]
=> [(1,'c'),(1,'e')]
minfst xs
在每一步都被重新计算,这是不必要的昂贵操作。我宁愿删除该参数,并使用 ... where minfst = minimum (map fst xs)
。 - chiminimum . map fst
是 fst . minimumBy (comparing fst)
的重新实现。 - Will Ness你进行了尝试
。minimumBy (comparing fst) xs
这也可以写成
= head . sortBy (comparing fst) $ xs
= head . sortOn fst $ xs
= head . head . group . sortOn fst $ xs
= head . head . groupBy ((==) `on` fst) . sortOn fst $ xs
head
即可获得所需结果。= head . groupBy ((==) `on` fst) . sortOn fst $ xs
head
是不好的,因为它会在输入[]
时出错。相反,我们可以使用安全选项。= concat . take 1 . groupBy ((==) `on` fst) . sortOn fst $ xs
顺便提一下,任何调用minimum
的解决方案对于空输入列表也是不安全的:
> head []
*** Exception: Prelude.head: empty list
> minimum []
*** Exception: Prelude.minimum: empty list
但是takeWhile
是安全的:
> takeWhile undefined []
[]
编辑:由于懒惰,最终版本的总时间复杂度即使在最坏情况下仍应为O(n)。
Data.OldList
似乎有使用插入排序进行sortBy
操作的选项(基于USE_REPORT_PRELUDE
的值),尽管在Haskell报告(1998或2010)中似乎没有提到排序。 - chepner