【发布时间】:2015-05-07 10:05:01
【问题描述】:
是否有一个 Haskell 函数接受一个列表并返回该列表中重复/冗余元素的列表?
我知道 nub 和 nubBy 函数,但它们删除重复项;我想保留这些骗子并将它们收集在一个列表中。
【问题讨论】:
标签: list haskell functional-programming
是否有一个 Haskell 函数接受一个列表并返回该列表中重复/冗余元素的列表?
我知道 nub 和 nubBy 函数,但它们删除重复项;我想保留这些骗子并将它们收集在一个列表中。
【问题讨论】:
标签: list haskell functional-programming
我编写了这些似乎运行良好的函数。
第一个返回具有基本相等性测试的列表中的重复元素列表 (==)
duplicate :: Eq a => [a] -> [a]
duplicate [] = []
duplicate (x:xs)
| null pres = duplicate abs
| otherwise = x:pres++duplicate abs
where (pres,abs) = partition (x ==) xs
第二个通过提供相等性测试功能(如nubBy)完成同样的工作
duplicateBy :: (a -> a -> Bool) -> [a] -> [a]
duplicateBy eq [] = []
duplicateBy eq (x:xs)
| null pres = duplicateBy eq abs
| otherwise = x:pres++duplicateBy eq abs
where (pres,abs) = partition (eq x) xs
【讨论】:
++;没必要,在这里。
++ 是一个足够好的经验法则。
Prelude.++ 几乎肯定比自己滚动要好。
最简单但效率极低的方法是使用nub和\\:
import Data.List (nub, (\\))
getDups :: Eq a => [a] -> [a]
getDups xs = xs \\ nub xs
如果您可以接受Ord 约束,一切都会变得更好:
import Data.Set (member, empty, insert)
getDups :: Ord a => [a] -> [a]
getDups xs = foldr go (const []) xs empty
where
go x cont seen
| member x seen = x : r seen
| otherwise = r (insert x seen)
【讨论】:
是否有一个 Haskell 函数接受一个列表并返回该列表中重复/冗余元素的列表?
您可以很容易地自己编写这样的函数。使用一个辅助函数,它接受两个列表参数,第一个是要寻找其欺骗的列表;沿着该列表走,并在第二个参数中累积欺骗;最后,当第一个参数为空列表时,返回后者。
dupes l = dupes' l []
where
dupes' [] ls = ls
dupes' (x:xs) ls
| not (x `elem` ls) && x `elem` xs = dupes' xs (x:ls)
| otherwise = dupes' xs ls
测试:
λ> dupes [1,2,3,3,2,2,3,4]
[3,2]
请注意,渐近时间复杂度与nub 一样糟糕,不过:O(n^2)。如果你想要更好的渐近线,你需要一个 Ord 类约束。
【讨论】:
如果您对 Ord 约束感到满意,您可以使用来自 Data.List 的 group:
getDups :: Ord a => [a] -> [a]
getDups = concatMap (drop 1) . group . sort
【讨论】:
getDups [1,2,1]
nub 只假设Eq,而不是Ord。
Data.List.nub 因此对于几乎所有应用程序来说都是错误的函数。