计算列表中的出现次数,然后将其返回到另一个列表中

时间:2019-04-06 10:07:14

标签: haskell functional-programming

我想做一个叫做countAll的函数。此函数应获取数字列表并返回一个列表(元素,出现次数)。例如 : countAll [1,2,3,4,4,4]应该返回 [(1,1),(2,1),(3,1),(4,3)] 我被迫使用下面发布的函数计数。

count :: Eq a=> a -> [a] -> Int
count e [] = 0
count e (x:xs) 
 | e == x = 1 + count e xs
 | otherwise = count e xs

3 个答案:

答案 0 :(得分:0)

使用快速的数据结构,例如Data.IntMultiSet。让ls = [1,2,3,4,4,4]

import qualified Data.IntMultiSet as IntMultiSet

IntMultiSet.fromList ls 

使用IntMap的替代方法:

import qualified Data.IntMap.Strict as IntMap

IntMap.fromListWith (+) [(k,1) | k <- ls]

答案 1 :(得分:0)

如果列表元素也是nub的实例,而不需要O(n^2)的繁琐机制,我们可以比Ord(即IntMultiSet)做得更好元素与sort一起,然后使用group将其分组为子列表。例如,group . sort $ [1,2,3,4,4,4]给出[[1], [2], [3], [4,4,4]]

一旦我们将这些项目组织到了子列表中,我们就可以计算每个子列表:

countAll = map (\(x:xs) -> (x, count x (x:xs))) . group . sort

(请注意,group保证不会有任何空的子列表,因此我们知道即使编译器不需要,我们也不需要检查映射函数中的[]大小写。 )

如果我们不需要使用count,可以改为使用

countAll = map (\xs -> (head xs, length xs)) . group . sort

,或者使用(&&&)中方便的Control.Arrow组合器,

countAll = map (head &&& length) . group . sort

由于association list个元素及其计数是表示bag的便捷方法,因此我喜欢称之为

bag = map (head &&& length) . group . sort

bagO(n log n),仅比IntMultiSet版本差一个对数因子。

答案 2 :(得分:-2)

一种方法是使用list comprehension

countAll xs = nub [(x, count x xs) | x <- xs]

nub删除重复项,您将需要import Data.List (nub)来使用它。