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

use*_*846 1 haskell count counting

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

签名可能是这样的:

countOccurences :: [a] -> [(a, Int)]
Run Code Online (Sandbox Code Playgroud)

例:

countOccurences [1, 1, 2, 3, 1, 2, 4] 
Run Code Online (Sandbox Code Playgroud)

结果是

[(1, 3), (2, 2), (3, 1), (4, 1)]
Run Code Online (Sandbox Code Playgroud)

(顺序并不重要)。

chi*_*chi 7

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

> group . sort $ [1, 1, 2, 3, 1, 2, 4] 
[[1,1,1],[2,2],[3],[4]]
Run Code Online (Sandbox Code Playgroud)

因此,

> map (head &&& length) . group . sort $ [1, 1, 2, 3, 1, 2, 4] 
[(1,3),(2,2),(3,1),(4,1)]
Run Code Online (Sandbox Code Playgroud)

因此,我们获得

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

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

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


Sim*_*ine 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..])
Run Code Online (Sandbox Code Playgroud)

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

我曾想过使用关联列表或一些哈希图,但是不变性会妨碍

Data.Map 是一个基于树的关联图,因此此表示可能适合您。

如果您想使用[(a, Int)]M.assocs可以将其转换为Data.Map

countOccurrences :: Ord a => [a] -> [(a, Int)]
countOccurrences = M.assocs . histogram
Run Code Online (Sandbox Code Playgroud)

  • 或`Data.HashMap`或`Data.IntMap`。无论选择哪种方式,都应使用严格的操作:将合格的Data.Map.Strict导入为M。 (4认同)
  • 或 `histogram = Foldl' (\mk -> M.insertWith (+) k 1 m) M.empty`,以消除对 `zip` 的需要。 (2认同)