将数组中的连续数字分组

时间:2014-05-24 02:42:13

标签: ruby arrays

我需要将连续数字添加到新数组中,如果它不是连续数字,则只将该值添加到新数组中:

old_array = [1, 2, 3, 5, 7, 8, 9, 20, 21, 23, 29]

我想得到这个结果:

 new_array = [
  [1,2,3],
  [5],
  [7,8,9]
  [20,21]
  [23],
  [29]
]

有更简单的方法吗?

7 个答案:

答案 0 :(得分:9)

这是RDoc中略有修改的官方答案:

actual = old_array.first
old_array.slice_before do
  |e|
  expected, actual = actual.next, e
  expected != actual
end.to_a

答案 1 :(得分:5)

这次聚会有点晚了但是:

old_array.slice_when { |prev, curr| curr != prev.next }.to_a
# => [[1, 2, 3], [5], [7, 8, 9], [20, 21], [23], [29]]

答案 2 :(得分:2)

其他几种方式:

old_array = [1, 2, 3, 5, 7, 8, 9, 20, 21, 23, 29]

<强>#1

a, b = [], []
enum = old_array.each
loop do
  b << enum.next
  unless enum.peek.eql?(b.last.succ)
    a << b
    b = []
  end
end
a << b if b.any?
a #=> [[1, 2, 3], [5], [7, 8, 9], [20, 21], [23], [29]]

<强>#2

def pull_range(arr)
  b = arr.take_while.with_index { |e,i| e-i == arr.first }
  [b, arr[b.size..-1]]
end

b, l = [], a
while l.any?
  f, l = pull_range(l)
  b << f
end
b #=> [[1, 2, 3], [5], [7, 8, 9], [20, 21], [23], [29]]

答案 3 :(得分:1)

有些答案看起来不必要很长,有可能以非常紧凑的方式做到这一点:

arr = [1, 2, 3, 5, 7, 8, 9, 20, 21, 23, 29]
arr.inject([]) { |a,e| (a[-1] && e == a[-1][-1] + 1) ? a[-1] << e : a << [e]; a }
# [[1, 2, 3], [5], [7, 8, 9], [20, 21], [23], [29]]

或者,从第一个元素开始去掉a[-1]条件(因a[-1]为空而nila时所需的情况:< / p>

arr[1..-1].inject([[arr[0]]]) { |a,e| e == a[-1][-1] + 1 ? a[-1] << e : a << [e]; a }
# [[1, 2, 3], [5], [7, 8, 9], [20, 21], [23], [29]]

Enumerable#inject迭代可枚举的所有元素,构建一个以给定对象开头的结果值。我给它一个空数组或一个数组,其中第一个值分别包含在我的解决方案中。然后我简单地检查我们正在迭代的输入数组的下一个元素是否等于结果数组中最后一个数组的最后一个值加1(即,如果它是下一个连续元素)。如果是,我将它附加到最后一个列表。否则,我会在其中开始一个包含该元素的新列表,并将其附加到生成的数组中。

答案 4 :(得分:0)

你也可以这样做:

old_array=[1, 2, 3, 5, 7, 8, 9, 20, 21, 23, 29]
new_array=[]
tmp=[]
prev=nil
for i in old_array.each
    if i != old_array[0]
        if i - prev == 1
            tmp << i
        else
            new_array << tmp
            tmp=[i]
        end
        if i == old_array[-1]
            new_array << tmp
            break
        end
        prev=i
    else
        prev=i
        tmp << i
    end
end

答案 5 :(得分:0)

使用chunk即可:

old_array.chunk([old_array[0],old_array[0]]) do |item, block_data|
  if item > block_data[1]+1
   block_data[0] = item
  end

  block_data[1] = item 
  block_data[0]
end.map { |_, i| i }
# => [[1, 2, 3], [5], [7, 8, 9], [20, 21], [23], [29]]

答案 6 :(得分:0)

使用哈希你可以:

counter = 0
groups = {}
old_array.each_with_index do |e, i|
  groups[counter] ||= []
  groups[counter].push old_array[i]
  counter += 1 unless old_array.include? e.next
end
new_array = groups.keys.map { |i| groups[i] }