2012-07-31 75 views
7

我试图根据各个值落在一个范围内的位置将一个整数数组分组为一个散列。基本上我想要将数组转换为固定宽度的直方图。Ruby Array to Histogram:如何按范围对数字进行分组?

实施例:

values = [1,3,4,4,4,4,4,10,12,15,18] 
bin_width = 3 

我被它们落入3单位宽桶像这样数组值成基于范围的historgram需要组:

{'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 2012-07-31 14:16:10

+3

应该没有痴迷写单行。争取只涉及表达式的解决方案(就是这样,使用功能性方法)是的,担心任务可以节省几条线,不。 – tokland 2012-07-31 14:30:07

回答

10
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]} 
+0

哈,我只是想建议一些不需要Facets的东西,然后你更新了你的帖子。 – 2012-07-31 14:16:12

+1

@迈克尔,对不起,实际上我的方面片段完全错误,map_by在这里没有用,我们需要处理键,而不是数值。这就是你如何写它? – tokland 2012-07-31 14:17:00

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 } } 
+0

感谢使用3单元垃圾箱的更一般版本,并且可以适应更多任意的情况。正是我需要的。 – slothbear 2017-04-16 02:28:55