我想做一个叫做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
答案 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
bag
是O(n log n)
,仅比IntMultiSet
版本差一个对数因子。
答案 2 :(得分:-2)
一种方法是使用list comprehension:
countAll xs = nub [(x, count x xs) | x <- xs]
nub
删除重复项,您将需要import Data.List (nub)
来使用它。