如何将范围分成N个部分

时间:2016-05-29 20:30:16

标签: ruby hash split range slice

我想知道如何将范围拆分为ruby中的N个部分,同时将它们添加到生成的每个范围的基于零值的哈希值。

例如:

range = 1..60
p split(range, 4)
#=> {1..15 => 0, 16..30 => 1, 31..45 => 2, 46..60 => 3}

我已经阅读How to return a part of an array in Ruby?了解了如何将一个范围切割成数组,还有一些关于如何将切片转换回范围的其他内容,但我似乎无法将所有碎片拼凑到一起创建我想要的方法。

感谢您的帮助

1 个答案:

答案 0 :(得分:5)

range = 1..60

range.each_slice(range.last/4).with_index.with_object({}) { |(a,i),h|
  h[a.first..a.last]=i }
  #=> {1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3}

步骤如下:

enum0 = range.each_slice(range.last/4)
  #=> range.each_slice(60/4)
  #   #<Enumerator: 1..60:each_slice(15)> 

您可以将此枚举器转换为数组,以查看它将生成的(4)元素并传递给each_with_index

enum0.to_a
  #=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
  #    [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
  #    [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45],
  #    [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]] 

enum1 = enum0.with_index
  #=> #<Enumerator: #<Enumerator: 1..60:each_slice(15)>:with_index>
enum1.to_a
  #=> [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0],
  #    [[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], 1],
  #    [[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], 2],
  #    [[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], 3]] 

enum2 = enum1.with_object({})
  #=> #<Enumerator: #<Enumerator: #<Enumerator: 1..60:each_slice(15)>
  #     :with_index>:with_object({})>
enum2.to_a
  #=> [[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], {}],
  #    [[[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], 1], {}],
  #    [[[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], 2], {}],
  #    [[[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], 3], {}]]

仔细检查enum1enum2计算的返回值。您可能希望将它们视为&#34;复合&#34;统计员。每个enum2四个数组的第二个和最后一个元素是由块变量h表示的空哈希。该哈希将在随后的计算中构建。

enum2.each { |(a,i),h| h[a.first..a.last]=i }
  #=> {1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3} 

enum2传递给块的each的第一个元素(执行enum.each...之前)是

arr = enum2.next
  #=>[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], {}]

使用并行分配(有时称为多次分配)将块变量分配给arr的元素

(a,i),h = arr
  #=> [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], {}] 
a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 
i #=> 0 
h #=> {}

因此块计算

h[a.first..a.last]=i 
  #=> h[1..15] = 0

现在

h #=> {1..15=>0} 

enum2生成的其他3个元素的每个元素的计算类似。

表达式

enum2.each { |(a,i),h| h[(a.first..a.last)]=i }

也可以写成

enum2.each { |((f,*_,l),i),h| h[(f..l)]=i }