打印在Haskell中重复的列表元素

时间:2013-09-08 08:31:16

标签: haskell

我想打印在列表中出现多次的元素。你能告诉我我该怎么办..我是哈斯克尔的新手。

例如,如果我有[1,2,3,3,2,4,5,6,5]我只想得到[2,3,5]因为这些是列表中的重复元素。 / p>

3 个答案:

答案 0 :(得分:2)

另一种解决方案:首先对列表进行排序,然后对相等的元素进行分组,并仅采用多次出现的元素:

>>> :m + Data.Maybe Data.List
>>> let xs = [1..100000] ++ [8,18..100] ++ [10,132,235]
>>> let safeSnd = listToMaybe . drop 1
>>> mapMaybe safeSnd $ group $ sort xs
[8,10,18,28,38,48,58,68,78,88,98,132,235]

group $ sort xs是列表,其中每个列表包含所有相等的元素。

mapMaybe safe2nd仅返回具有第二个元素的列表(= orignal元素在原始列表中出现多次)。

这种方法应该比使用nub的方法更快,特别是对于大型列表。

答案 1 :(得分:2)

Data.Map.Lazy and Data.Map.Strict是一堆有趣的函数,用于构建地图(关联地图,字典,无论你想要什么称呼它们)。其中一个是fromListWith

fromListWith :: Ord k => (a -> a -> a) -> [(k, a)] -> Map k a

您要构建的是一张地图,告诉您输入列表中的每个值,它发生的频率。值将是地图的键(类型k),它们的计数将是与键相关联的值(类型a)。您可以使用以下表达式:

fromListWith (+) . map (\x -> (x, 1))

首先,列表中的所有值都会被放入元组中,并且计数为1。然后,fromListWith从列表中构建一个地图;如果密钥已存在,则使用(+)计算新计数。

完成此操作后,您只对多次出现的元素感兴趣。为此,您可以使用filter (> 1)中的Data.Map

最后,您只想知道地图中剩余的所有键。使用函数keys来实现此目的。


最后,您将获得以下模块:

import qualified Data.Map.Strict as M

findDuplicates :: (Ord a) => [a] -> [a]
findDuplicates
    = M.keys
    . M.filter (> 1)
    . M.fromListWith (+)
    . map (\x -> (x, 1 :: Integer))

通常的做法是导入某些类似Data.Map的软件包,以避免模块之间的名称冲突(例如filter来自Data.Map而来自Prelude的密码非常不同) 。在这种情况下,最好选择Data.Map.Strict;请参阅Data.Map顶部的解释。

此方法的复杂性应为O(n log n)

我认为可以通过使用布尔标志来优化它,以指示该值是重复的。然而,结果大约慢了20%。

答案 2 :(得分:1)

您基本上在寻找不唯一的元素列表,换句话说,原始列表与唯一元素列表之间的差异。在代码中:

xs \\ (nub xs)

如果您不想在结果列表中包含重复项,则需要再次致电nub

nub $ xs \\ (nub xs)