如何将整数数组汇总为范围数组?

我想接受以下输入:

[1,2,4,5,6,7,9,13] 

把它变成如下的东西:

 [[1,2],[4,7],[9,9],[13,13]] 

每个子数组代表一个整数范围。

使用Enumerable#chunk的function方法:

 ranges = [1, 2, 4, 5, 6, 7, 9, 13] .enum_for(:chunk) # .chunk for Ruby >= 2.4 .with_index { |x, idx| x - idx } .map { |_diff, group| [group.first, group.last] } #=> [[1, 2], [4, 7], [9, 9], [13, 13]] 

它是如何工作的:一旦索引,数组中的连续元素具有相同的x - idx ,所以我们使用该值来对输入数组进行块(连续项的分组)。 最后,我们只需要采用每个组的第一个和最后一个元素来构建对。

这几乎可以直接来自可枚举的#lif_before方法文档:

 ar = [1,2,4,5,6,7,9,13] prev = ar[0] ar.slice_before{|e|prev,prev2 = e,prev; prev2.succ != e}.map{|a|a.first..a.last} #=> [1..2, 4..7, 9..9, 13..13] 

这应该与字符,日期,任何使用.succ方法的东西一起使用。

比@ tokland更好的解决方案是使用chunk_while

 xs.chunk_while { |a, b| a + 1 == b }.map do |seq| [seq.first, seq.last] end 

注意chunk_while是在Ruby 2.3中引入的

嗯,这不是托克兰的杰作,但我认为这可能是一个很好的直接解决方案……

 [1,2,4,5,6,7,9,13].inject([]) do |m, v| if m.last.to_a.last == v.pred m[-1][-1] = v else m << [v, v] end m end 

另一种方法

 def summarize(x) x.inject([]) do |acc, value| if acc.last && acc.last[1] + 1 == value acc.last[1] = value acc else acc << [value,value] end end end 

类似于Larsenal的方法,但使用注入来管理无聊的东西。