是否有一个函数接受一个列表和 returns 该列表中重复元素的列表?

Is there a function that takes a list and returns a list of duplicate elements in that list?

是否有一个 Haskell 函数接受一个列表和 returns 该列表中 duplicates/redundant 个元素的列表?

我知道 nubnubBy 函数,但它们 删除了 重复项;我想保留这些骗子并将它们收集在一个列表中。

Is there a Haskell function that takes a list and returns a list of duplicates/redundant elements in that list?

你自己写一个这样的函数就够轻松的了。使用一个带有两个列表参数的辅助函数,第一个是要查找其欺骗对象的列表;沿着那个列表走,并在第二个参数中积累欺骗;最后,return 后者,当第一个参数是空列表时。

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 class 约束。

如果您对 Ord 约束感到满意,您可以使用 Data.List 中的 group:

getDups :: Ord a => [a] -> [a]
getDups = concatMap (drop 1) . group . sort

执行此操作的最简单方法(效率极低)是使用 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)

我写了这些函数,看起来运行良好。

第一个return列表中的重复元素列表,具有基本的相等性测试(==)

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