将范围分成 X 组
Splitting a range into X groups
我需要将一个范围分成 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]
所以我可能会迭代数组以将它们传递给 Net::HTTP
库中的 set_range
方法。
我正在处理的范围与 0..46000000
一样大或更大,因为我正在处理以字节为单位的文件大小。
如有任何帮助,我们将不胜感激。
像这样?
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]
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
这将确保没有范围的大小与任何其他范围的大小相差超过一个:
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]
我需要将一个范围分成 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]
所以我可能会迭代数组以将它们传递给 Net::HTTP
库中的 set_range
方法。
我正在处理的范围与 0..46000000
一样大或更大,因为我正在处理以字节为单位的文件大小。
如有任何帮助,我们将不胜感激。
像这样?
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]
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
这将确保没有范围的大小与任何其他范围的大小相差超过一个:
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]