如何在haskell中分组和统计?

时间:2015-08-30 20:09:22

标签: haskell

给定一个列表(例如[1,2,2,3,3,4,5,6])如何根据bin / range对它们进行分组和计数?我希望能够指定范围,以便:

假设范围= 2,并使用上一个列表,给我[1, 4, 2, 1],假设有1 0或1,4 2或2或者3岁,2岁,5岁以上,1岁6岁或7岁以上。

假设范围= 4,并使用前面的列表,给我[5,3],假设有5 0或1或2或3&3 #39; s,3 4&s;或5&s;或6&s;或7'

我调查了groupgroupBy但找不到合适的谓词,还找到了直方图填充库。后者似乎非常适合创建垃圾箱,但我无法找到如何将数据加载到这些垃圾箱中。

我怎样才能做到这一点?

我尝试了以下建议之一:

import Data.List 
import Data.Function 

quantize range n = n `div` range  

main = print (groupBy ((==) `on` quantize 4) [1,2,3,4,2]) 

输出是[[1,2,3],[4],[2]],应该是[[1,2,2,3],[4]]。以下两个建议都适用于排序列表。

main = print (groupBy ((==) `on` quantize 4) (sort [1,2,3,4,2]))   

2 个答案:

答案 0 :(得分:3)

您可以使用groupBydiv功能实现此目的。假设我们有一个范围N。如果我们得到div个连续数的积分(N),那么所有这些都应该相等。例如,N=30 div 3 = 0, 1 div 3 = 0, 2 div 3 = 0, 3 div 3 = 1, 4 div 3 = 1, 5 div 3 = 1, 6 div 3 = 2

了解这一点,我们可以查看groupBy :: (a -> a -> Bool) -> [a] -> [[a]]并使用函数:

sameGroup :: Integral a => a -> a -> a -> Bool
sameGroup range a b = a `div` range == b `div` range

编写我们自己的分组功能

groupings :: Integral a => a -> [a] -> [[a]]
groupings range = groupBy (sameGroup range)

其中应该类似于groupings 2 [1, 2, 2, 3, 3, 4, 5, 6] == [[1], [2, 2, 3, 3], [4, 5], [6]]。现在我们只需要计算它以获得最终功能

groupAndCount :: Integral a => a -> [a] -> [Int]
groupAndCount range list = map length $ groupings range list

哪个应该反映出想要的行为。

答案 1 :(得分:3)

您需要量化才能获得垃圾箱的定义。

-- `quantize range n` rounds n down to the nearest multiple of range
quantize :: Int -> Int -> Int

groupBy采用“谓词”参数*,它标识是否应将两个项目放在同一个bin中。所以:

groupBy (\n m -> quantize range n == quantize range m) :: [Int] -> [[Int]]

将根据元素是否在同一个bin中对元素进行分组,而不更改元素。如果range为2,则会为您提供类似

的内容
[[1],[2,2,3,3],[4,5],[6]]

然后你只需要取每个子列表的length

* 有一个称为on的简洁函数,它允许您更简洁地编写谓词

groupBy ((==) `on` quantize range)