How do I summarize array of integers as an array o

2019-01-24 10:09发布

I'd like to take input such as:

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

and turn it into something like the following:

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

Each sub-array represents a range of integers.

5条回答
欢心
2楼-- · 2019-01-24 10:15

An even easier solution than @tokland's very nice one is using chunk_while:

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

Note: chunk_while was introduced in Ruby 2.3

查看更多
仙女界的扛把子
3楼-- · 2019-01-24 10:18

Functional approach using Enumerable#chunk:

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]]

How it works: once indexed, consecutive elements in the array have the same x - idx, so we use that value to chunk (grouping of consecutive items) the input array. Finally we just need to take the first and last elements of each group to build the pairs.

查看更多
家丑人穷心不美
4楼-- · 2019-01-24 10:24

Hmm, well, it's not tokland's masterpiece, but I think it may be a good straightforward solution...

[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
查看更多
Ridiculous、
5楼-- · 2019-01-24 10:25

This is almost straight from the enumerable#slice_before method documentation:

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]

This should work with characters, dates, anything with a .succ method.

查看更多
女痞
6楼-- · 2019-01-24 10:35

Another approach

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

Similar to Larsenal's method but using inject to manage the boring stuff.

查看更多
登录 后发表回答