我需要将一个范围拆分为X个组,并且我很难找到一种不使用数组的方法,因为这些范围可能非常大。
我目前的解决方案是创建一个超出范围的数组,然后用一些数学运算调用它上面的each_slice
,将数据分成大小相同的X个组,具体取决于有多少组
irb(main):026:0> a = (0..10)
=> 0..10
irb(main):027:0> a.each_slice( (a.size/3.0).round ).to_a
=> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10]]
irb(main):028:0> a.each_slice( (a.size/5.0).round ).to_a
=> [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10]]
这个问题是,当范围过大时,应用程序将因为分割数组所需的计算而挂起。
我真正需要的是这种格式的数组(考虑a.size / 3.0 3组示例):
[0..3, 4..7, 8..10]
因此,我可以迭代数组,将它们传递给set_range
库中的Net::HTTP
方法。
我处理的范围与0..46000000
一样大或大,因为我处理的是文件大小(以字节为单位)。
任何帮助都将不胜感激。
答案 0 :(得分:0)
喜欢这个吗?
def split_ranges(amount, max)
(0...amount).collect{|i| (i * max / amount)...((i+1) * max / amount)}
end
p split_ranges(3, 46000000)
输出:
[0...15333333, 15333333...30666666, 30666666...46000000]
编辑:(OP请求)
def split_ranges(amount, max)
(0...amount).collect{|i| (i * (max + 1) / amount)..((i + 1) * (max + 1) / amount - 1)}
end
p split_ranges(3, 46000000)
输出:
[0..15333332, 15333333..30666666, 30666667..46000000]
答案 1 :(得分:0)
class Range
def each_subrange(n)
return to_enum(:each_subrange, n) unless block_given?
range_size = size
range_begin = self.begin
n.times do |i|
yield range_begin + range_size * i / n .. range_begin + range_size * (i + 1) / n - 1
end
end
end
a = 0..46000000
# without a block
puts a.each_subrange(3).to_a
# with a block
a.each_subrange(3) do |r|
puts r
end
答案 2 :(得分:0)
这将确保没有范围与任何其他范围的大小相差多于一个:
def split_it(r, n)
return [r] if n == 1
last = r.first - 1 + (r.last-r.first+1)/n
[r.first..last].concat(split_it(last+1..r.last, n-1))
end
r = 0..46000000
split_it(r, 3)
#=> [0..15333332, 15333333..30666666, 30666667..46000000]
split_it(r, 3).map(&:size)
#=> [15333333, 15333334, 15333334]
split_it(r, 4)
#=> [0..11499999, 11500000..22999999, 23000000..34499999,
# 34500000..46000000]
split_it(r, 4).map(&:size)
# => [11500000, 11500000, 11500000, 11500001]
split_it(r, 5)
#=> [0..9199999, 9200000..18399999, 18400000..27599999,
# 27600000..36799999, 36800000..46000000]
split_it(r, 5).map(&:size)
#=> [9200000, 9200000, 9200000, 9200000, 9200001]