This is my approach to solving your problem. Let be
a = [1012..1014, 1016..1020, 1017..1022, 1021..1035, 1040..1080]
Step 1: Smooth this array, then count each element
b = a.map(&:to_a).inject(:+).sort.group_by{|i| i }.map{|k,v| [k,v.count] }
Step 2: Add Zero As Breakpoints
c = b.each_with_index do |e, i| if e.nil? || b[i+1].nil? then next end if b[i][0] + 1 != b[i+1][0] || b[i][1] != b[i+1][1] then b.insert(i+1,nil) end end # => [[1012, 1], [1013, 1], [1014, 1], nil, [1016, 1], nil, [1017, 2], [1018, 2], [1019, 2], [1020, 2], [1021, 2], [1022, 2], nil, [1023, 1], ...
Step 3: Divide the resulting array into breakpoints and group them into ranges
d = c.split{|e| e.nil?}.map{|e| [(e.first[0]..e.last[0]), e.first[1]]}
Update:
Since split is a method from Rails, so I have an alternative with pure Ruby.
Step 1: as above
Step 2: Divide the array into small groups as shown below
c = [] j = 0 b.each_with_index do |e, i| if c[j].nil? then c[j] =[] end c[j] << b[i] if b[i+1] && (b[i][0] + 1 != b[i+1][0] || b[i][1] != b[i+1][1]) then j+=1 end end # pc => [ # [[[1012, 1], [1013, 1], [1014, 1]], # [[1016, 1]], # [[1017, 2], [1018, 2], [1019, 2], [1020, 2], [1021, 2], [1022, 2]], # ... # ]
Step 3: Convert Each Group To A Range
d = c.map{|e| [(e.first[0]..e.last[0]), e.first[1]]}