给定一个列表(例如[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'
我调查了group
和groupBy
但找不到合适的谓词,还找到了直方图填充库。后者似乎非常适合创建垃圾箱,但我无法找到如何将数据加载到这些垃圾箱中。
我怎样才能做到这一点?
我尝试了以下建议之一:
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]))
答案 0 :(得分:3)
您可以使用groupBy
和div
功能实现此目的。假设我们有一个范围N
。如果我们得到div
个连续数的积分(N
),那么所有这些都应该相等。例如,N=3
,0 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)