Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to break a range down into smaller non-overlapping ranges

Tags:

ruby

What is the most beautiful way to break a larger range into smaller non overlapping ranges?

range = 1..375

Desired Output:

1..100
101..200
201..300
301..375
like image 617
Tom Rossi Avatar asked Dec 10 '19 19:12

Tom Rossi


2 Answers

You can use #each_slice in combination with #map:

(1..375).each_slice(100).map { |a,*,b| (a..b) }     

#=> [1..100, 101..200, 201..300, 301..375]
like image 59
Viktor Avatar answered Oct 22 '22 18:10

Viktor


The following may not be the most elegant solution but it is designed to be relatively efficient, by avoiding the creation of temporary arrays.

def divide_range(range, sz)
  start = range.begin
  (range.size/sz).times.with_object([]) do |_,arr|
    arr << (start..start+sz-1)
    start += sz
  end.tap { |arr| (arr << (start..range.end)) if start < range.end }
end

divide_range(1..375, 100)
  #=> [1..100, 101..200, 201..300, 301..375] 
divide_range(1..400, 100)
  #=> [1..100, 101..200, 201..300, 301..400] 
divide_range(50..420, 50)
  #=> [50..99, 100..149, 150..199, 200..249, 250..299, 300..349,
  #    350..399, 400..420]
n = 1_000_000_000_000
divide_range(1..n, n/2)
  #=> [1..500000000000, 500000000001..1000000000000] 
like image 2
Cary Swoveland Avatar answered Oct 22 '22 17:10

Cary Swoveland