Search code examples
arraysrubynomethoderror

Ruby: NoMethodError when comparing element in an array


I'm working on a method that takes an array of words as a param and returns an array of arrays, where each subarray contains words that are anagrams of each other. The line while sort_array[i][1]==temp do is throwing undefined method '[]' for nil:NilClass (NoMethodError) and I have no idea why.

def combine_anagrams(words)
sort_array = Hash.new

words.each do |w|
    sort_array[w] = w.split("").sort
end

sort_array = sort_array.sort_by { |w, s| s }

return_array = []
i = 0
while i<sort_array.length do
    temp_array = []
    temp = sort_array[i][1]
    while sort_array[i][1]==temp do
        temp_array += [sort_array[i][0]]
        i+=1
    end
    return_array += [temp_array]
end

return temp_array
end

p combine_anagrams( ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams','scream'] )

Solution

  • It looks like this is because you are incrementing your i variable without checking to make sure you're still in bounds of the sort_array. To see the problem, put an puts statement in your code inside the inner most while loop:

    while sort_array[i][1]==temp do
      temp_array += [sort_array[i][0]]
      i+=1
      puts "i is #{i} and the length is #{sort_array.length}"
    end
    

    and then run your code and you'll see:

    i is 1 and the length is 8
    i is 2 and the length is 8
    i is 3 and the length is 8
    i is 4 and the length is 8
    i is 5 and the length is 8
    i is 6 and the length is 8
    i is 7 and the length is 8
    i is 8 and the length is 8
    example.rb:15:in `combine_anagrams': undefined method `[]' for nil:NilClass (NoMethodError)
    

    You need to make sure on both while loops that you stay within the bounds of your array, for instance:

    while i < sort_array.length && sort_array[i][1]==temp do
    end
    

    As a side note, your code is currently only going to return the last temp_array, since you're also resetting that at the beginning of your outer while loop. And, if I understand what problem you're trying to solve you might want to look at group_by available on Array thanks to the Enumerable module:

    words = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams','scream']
    words.group_by { |word| word.chars.sort }.values
    # => [["cars", "racs", "scar"], ["for"], ["potatoes"], ["four"], ["creams", "scream"]]