2014-05-24 139 views
2

我需要连续号码添加到新阵列,如果它是不连续的号码,只值添加到一个新的数组:连续的分组编号在数组

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

是否有更简单的方法来做到这一点

+3

这是学校?你有什么尝试?你在寻求帮助还是为了我们为你做? – DutGRIFF

+0

'new_array'的条件? –

+0

相关问题:http://stackoverflow.com/q/3728660/38765 –

回答

8

这是RDoc给出(略有修改),官方的回答:

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

如何在ruby 1.8.7中编写代码? – bluexuemei

+2

Ruby 1.8.7不再被维护,并且包含几个已知的安全漏洞。你应该避免使用它。 –

+0

很好的答案,谢谢 – bluexuemei

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

可能不应该这样说,但那先生是一件艺术品! –

+0

感谢恭维,@约翰。 (约翰指的是#1;后来我加了#2)。 –

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 
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]] 
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]nil,因为a是空的):

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(即,如果它是下一个连续元素)。如果是,我将它追加到最后一个列表中。否则,我用它中的那个元素开始一个新的列表,并将它追加到结果数组中。

+0

很好的答案,谢谢 – bluexuemei

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

有点晚了这个晚会,但是:

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

+1。 'slice_when'被[添加](https://bugs.ruby-lang.org/issues/9826)到ruby版本'2.2',并且提供了比这些旧的答案更优雅的解决方案。 –