如何有效地计算列表中每个元素的所有出现次数?我曾想过使用关联列表或一些哈希图,但是不可变性会成为障碍,而且还不清楚如何(希望)有一个优雅的解决方案。
签名可能是这样的:
countOccurences :: [a] -> [(a, Int)]
示例:
countOccurences [1, 1, 2, 3, 1, 2, 4]
结果
[(1, 3), (2, 2), (3, 1), (4, 1)]
(顺序并不重要)。
答案 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