计算列表中每个元素的所有出现次数

时间:2019-03-13 14:09:32

标签: haskell count counting

如何有效地计算列表中每个元素的所有出现次数?我曾想过使用关联列表或一些哈希图,但是不可变性会成为障碍,而且还不清楚如何(希望)有一个优雅的解决方案。

签名可能是这样的:

countOccurences :: [a] -> [(a, Int)]

示例:

countOccurences [1, 1, 2, 3, 1, 2, 4] 

结果

[(1, 3), (2, 2), (3, 1), (4, 1)]

(顺序并不重要)。

2 个答案:

答案 0 :(得分:7)

group . sort将产生一个输出列表,例如

> group . sort $ [1, 1, 2, 3, 1, 2, 4] 
[[1,1,1],[2,2],[3],[4]]

因此

> map (head &&& length) . group . sort $ [1, 1, 2, 3, 1, 2, 4] 
[(1,3),(2,2),(3,1),(4,1)]

所以,我们获得了

import Data.List (group, sort)
import Control.Arrow ((&&&))

countOccurences :: Ord a => [a] -> [(a, Int)]
countOccurences = map (head &&& length) . group . sort

应该只需要O(n log n)时间。

答案 1 :(得分:5)

由于chi使用group . sort提供了一种解决方案,因此以下是使用Data.Map的解决方案:

import qualified Data.Map.Strict as M
import           Data.Map.Strict (Map)

histogram :: Ord a => [a] -> Map a Int
histogram = M.fromListWith (+) . (`zip` [1,1..])

这也使用了 O(n log n)时间。

  

我曾考虑使用关联列表或某些哈希图,但是不可变性会妨碍我们

Data.Map是一个基于树的关联图,所以这种表示可能适合您。

如果您希望使用[(a, Int)]M.assocs可以将Data.Map转换回:

countOccurrences :: Ord a => [a] -> [(a, Int)]
countOccurrences = M.assocs . histogram