Ruby数组直方图:如何按范围分组数字?

7
我将尝试根据整数数组中各个值所处的范围将其分组为哈希表。基本上,我想将数组转换为固定宽度的直方图。
例子:
values = [1,3,4,4,4,4,4,10,12,15,18]
bin_width = 3

我需要将数组值按照它们所属的3个单位宽度桶分组到基于范围的直方图中,如下所示:
{'0..2'=>[1,3],'3..5'=>[4,4,4,4,4],'6..8'=>[],'9..11'=>[10]....

这里是否有一个简单的一行解决方案(可能类似于values.group_by{|x| #range calc}),可在这里起作用?

1
问题:1)我猜3应该在3..5之间。2)为什么使用字符串作为键而不是真实的范围?3)你也需要空范围吗? - tokland
3
不应过于追求写一行代码的偏执。应该努力寻找只涉及表达式(即使用函数方法)的解决方案,而不是因为节省几行代码而害怕进行分配。 - tokland
2个回答

11
values = [1, 7, 2, 8, 2]
values.group_by { |x| x / 3 }.map { |k, vs| [(3*k..3*k+2), vs] }.to_h
#=> {0..2=>[1, 2, 2], 6..8=>[7, 8]}

如果你确实需要空范围,我认为不可能有一个干净的一行代码。但是这应该可以:

grouped = values.group_by { |x| x / 3 }
min, max = grouped.keys.minmax
(min..max).map { |n| [(3*n..3*n+2), grouped.fetch(n, [])] }.to_h
#=> {0..2=>[1, 2, 2], 3..5=>[], 6..8=>[7, 8]}

哈哈,我刚想建议一些不需要 Facets 的东西,然后你就更新了你的帖子。 - Michael Kohl
1
@Michael,是的,抱歉,事实上我的facets代码片段完全错误,map_by在这里没有用处,我们需要处理键而不是值。你会这样写吗? - tokland

4
我想到了一种效率不高但相当清晰的解决方案:
ranges = 0.step(values.max, bin_width).each_cons(2).map { |s, e| Range.new(s, e, true) }
values.group_by { |v| ranges.find { |r| r.cover? v } }

谢谢你提供更通用的版本,它可以适用于3个单位的箱子,并且可以适应更多任意情况。正是我所需要的。 - slothbear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接