如何将整数数组汇总为范围数组?
我想接受以下输入:
[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的方法,但使用注入来管理无聊的东西。