Jack Kelly Jack Kelly - 1 month ago 5
Ruby Question

I am receiving nil values in my small recursion method

The basic premise of the method is for the argument array to take a multidimensional array and snake around the matrix clockwise pushing all values into arr and returning them as a list of integers.

However,I seem to be receiving this error:

`block in snail': undefined method `reverse' for nil:NilClass (NoMethodError)


This is my method:

def snail(array)

arr = []
loop do
return arr.flatten if array.empty?
arr << array.shift
array.map {|row| arr << row.pop}
arr << array.pop.reverse
array.map {|row| arr << row.shift}

end

end


This is the test argument:

[[1,2,3],[4,5,6],[7,8,9]


This is the output i get when i edit line 5 to this:

line 5: arr << unless NilClass then array.pop.reverse end
output: [1, 2, 3, 6, 9, nil, 4, 7, 5, 8, nil, nil]


Expected return:

[1, 2, 3, 6, 9, 8, 7, 4, 5]


Why are these nil values appearing?

Answer

The problem is that on your second iteration, array becomes empty after arr << array.shift so the next two lines are executing on an empty array. The error you're seeing is because array.pop on the eighth line of the method has nothing to pop and so returns nil and nil does not support #reverse.

You need to handle that array can become depleted at any stage, not just after all four operations are executed.

def snail(array)
  arr = []
  until array.flatten.empty?
    arr << array.shift
    array.map {|row| arr << row.pop} unless array.flatten.empty?
    arr << array.pop.reverse unless array.flatten.empty?
    array.map {|row| arr << row.shift} unless array.flatten.empty?
  end
  return arr.flatten
end

Incidentally... I think the snail going back up on the left side is not correctly coded. You have to read the numbers from bottom to top, so, the last line of the loop should be...

array.reverse.map {|row| arr << row.shift} unless array.flatten.empty?

The problem doesn't show on your test argument but you'll see the issue if you try a larger matrix, like

[[1,2,3,4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

Your method gives... [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 5, 9, 6, 7]

But correct answer is... [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7]

Comments