Home > Software engineering >  Trying to run each_index on an array but getting `each': can't iterate from NilClass (Type
Trying to run each_index on an array but getting `each': can't iterate from NilClass (Type

Time:02-10

I am currently attempting the codewars 6th kyu kata "Equal Sides Of An Array" where it asks:

'Input: An integer array of length 0 < arr < 1000. The numbers in the array can be any integer positive or negative.

Output: The lowest index N where the side to the left of N is equal to the side to the right of N. If you do not find an index that fits these rules, then you will return -1.

Note: If you are given an array with multiple answers, return the lowest correct index.'

I know my code doesn't work completely but trying to run the code to see where it is going wrong to try and get a further understanding of how to use error codes to guide my thought process.

My code is as follows

def find_even_index(arr)
  even_index = -1
  arr.with_each_index do |n, index|
    even_index = index if (arr[0]..arr[index - 1]).sum == (arr[index   1]..arr[-1]).sum
  end
  even_index
end

When I input this into the kata to test, I get the following error:

'./lib/solution.rb:4:in `each': can't iterate from NilClass (TypeError)'

This error leads me to believe that there is an issue with the use of each_with_index on arr but the parameter is an array. What is going wrong here?

CodePudding user response:

There is not with_each_index in Ruby, only each_with_index

Your problem is in arr[index 1]..arr[-1] on last index

arr[index 1] in that case is nil so you tries nil..arr[-1]

That's why you have can't iterate from NilClass (TypeError) error

You don't need to use ranges in your solution, just use subarrays, array also have sum method

So you can use each_index method here like this:

def find_even_index(ary)
  ary.each_index do |idx|
    return idx if ary[...idx].sum == ary[idx   1..].sum
  end

  -1
end

find_even_index([1, 2, 3, 4, 3, 2, 1])
# => 3

find_even_index([1, 2, 2, 4, 3, 2, 1])
# => -1

This solution with beginless (available in Ruby >= 2.7) and endless (available in Ruby >= 2.6) ranges

In earlier versions you can use ary[0...idx] and ary[idx 1..-1]

CodePudding user response:

Here's a solution that does not repeatedly sum each side of a partitioned array.

Note that the Kata defines the sum of the elements before the first and after the last to equal zero.

def doit(arr)
  left = 0
  right = arr.sum - arr[0]
  (0..arr.size-1).each do |i|
    return i if left == right
    return -1 if i == arr.size - 1
    left  = arr[i]
    right -= arr[i 1]
  end
end
doit [1, 2, 3, 4, 3, 2, 1]
  #=> 3
doit [1, 2, 3, -5]
  #=> 0
doit [1, -3, 2, 18]
  #=> 3
doit [99]
  #=> 0
doit [0,0,0,0,0]
  #=> 0
doit [1, 2, 2, 4, 3, 2, 1]
  #=> -1

I can best explain the calculations by executing the method after having salted it with puts statements.

def doit(arr)
  puts "arr.size == #{arr.size}, arr.sum = #{arr.sum}" 
  left = 0
  right = arr.sum - arr[0]
  puts "initially left = 0, right = #{right}"       
  (0..arr.size-1).each do |i|
    puts "i = #{i}"
    puts left == right ?
      "returning #{i} because left == right" : "left != right"
    return i if left == right       
    puts  i == arr.size - 1 ? "  i == arr.size - 1 so returning #{-1}" :
       "  i < arr.size - 1, so continuing"
    return -1 if i == arr.size - 1
    left  = arr[i]
    puts "  left = left   arr[#{i}] = #{left} for i = #{i 1}"
    right -= arr[i 1]
    puts "  right = right - arr[#{i 1}] = #{right} for i = #{i 1}"
  end
end
doit [1, 2, 3, 4, 3, 2, 1]
  #=> 3
arr.size == 7, arr.sum = 16
initially left = 0, right = 15
i = 0
left != right
  i < arr.size - 1, so continuing
  left = left   arr[0] = 1 for i = 1
  right = right - arr[1] = 13 for i = 1
i = 1
left != right
  i < arr.size - 1, so continuing
  left = left   arr[1] = 3 for i = 2
  right = right - arr[2] = 10 for i = 2
i = 2
left != right
  i < arr.size - 1, so continuing
  left = left   arr[2] = 6 for i = 3
  right = right - arr[3] = 6 for i = 3
i = 3
returning 3 because left == right
  •  Tags:  
  • ruby
  • Related