我想打印在列表中出现多次的元素。你能告诉我我该怎么办..我是哈斯克尔的新手。
例如,如果我有[1,2,3,3,2,4,5,6,5]我只想得到[2,3,5]因为这些是列表中的重复元素。 / p>
答案 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)