Select consecutive integers from array in Ruby

I want to select consecutive integers from an array, for example:

Input: (doesn’t have to be sorted)

array = [1, 3, 6, 7, 8, 9, 10, 12, 13, 17]

Expected output:

#=> [6, 7, 8, 9, 10, 12, 13]

This is my code so far:

array = [1, 3, 9, 6, 7, 10, 8, 12, 13, 17]
newarray = []
z = 0
array.sort.each_cons(2) do |x, y|
  if y == x + 1
    if z == 0
      newarray.insert(0, x, y)
    else
      newarray.push(y)
    end
  end
  z = z + 1
end

newarray #=> [7, 8, 9, 10, 13]

As you can see, 6 and 12 are missing.

What’s wrong with my code and – besides the bug – is there a better way to write it?

  • How do I replace all the values in a hash with a new value?
  • Undefined namespace prefix in Nokogiri and XPath
  • Why I don't see gem list after correctly installed rbenv?
  • Rmagick can't continue.I can't get this gem working on Windows
  • Bundler installation failing with saltstack gem state
  • Best gem for working with ncurses and ruby
  • How do I remove emoji from string
  • devise routing error
  • One Solution collect form web for “Select consecutive integers from array in Ruby”

    Your code compares adjacent elements x and y, but pushes x and y only if they are the first elements in the array (if z == 0; newarray.insert(0, x, y)). Otherwise, only y is pushed, so the first element of each group of consecutive integers is missing.

    This table illustrates what’s going on:

      x   y   y == x+1
    --------------------
      1   3   false
      3   6   false
      6   7   true      #=> push(7)
      7   8   true      #=> push(8)
      8   9   true      #=> push(9)
      9  10   true      #=> push(10)
     10  12   false
     12  13   true      #=> push(13)
     13  17   false
    

    You could fix your code by using z as an indicator for the beginning of a group:

    z = true
    array.sort.each_cons(2) do |x, y|
      if y == x + 1
        if z
          newarray.push(x, y)
          z = false
        else
          newarray.push(y)
        end
      else
        z = true
      end
    end
    

    A better way is to use chunk_while that was introduced in Ruby 2.3:

    array = [1, 3, 9, 6, 7, 10, 8, 12, 13, 17]
    
    array
      .sort                              #=> [1, 3, 6, 7, 8, 9, 10, 12, 13, 17]
      .chunk_while { |x, y| y == x + 1 } #=> [[1], [3], [6, 7, 8, 9, 10], [12, 13], [17]]
      .select { |a| a.size > 1 }         #=> [[6, 7, 8, 9, 10], [12, 13]]
      .flatten                           #=> [6, 7, 8, 9, 10, 12, 13]
    

    Did you notice that the documentation contains a similar example?

    For example, one-by-one increasing subsequence can be chunked as follows:

    a = [1,2,4,9,10,11,12,15,16,19,20,21]
    b = a.chunk_while {|i, j| i+1 == j }
    p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
    
    Ruby is the best programming language in the world - Ruby on Rails.