This program takes two arrays of strings and subtracts the length of the longest in a1 from the shortest in a2, and then vice-versa and returns the greater.
It works (passed 103/103 tests), but I'm getting this error:
NoMethodError: undefined method `length' for nil:NilClass
main.rb:10:in `mxdiflg'
main.rb:66:in `block (2 levels) in <main>'
Where's the issue? And since this isn't the first time this has happened, how do I debug a program that works?
def mxdiflg(a1, a2)
if a1 == '' || a2 == ''
-1
end
a1_order = a1.sort{|left, right| left.length <=> right.length}
a2_order = a2.sort{|left, right| left.length <=> right.length}
a_total = a1_order.reverse[0].length - a2_order[0].length
b_total = a2_order.reverse[0].length - a1_order[0].length
if b_total > a_total
b_total
else
a_total
end
end
Starting with fixing your program. First of all, you say you're accepting arrays of strings, yet if a1 == '' || a2 == ''
checks whether you passed empty strings. Putting -1
, not a return -1
does essentially nothing.
I am assuming that the error is in this line (you have the line in stacktrace, it's main.rb:10:in 'mxdiflg'
therefore line 10 for you):
a_total = a1_order.reverse[0].length - a2_order[0].length
As if your array is empty, your array[0]
will be nil
so you cannot call .length
on it (just as the error you pasted says suggest).
As for debugging, at some point you will have to get comfortable with using Pry, but for now it should be enough that you check the line number and error message. In this case, it's quite clear that you're calling .length
on a nil
, so your a1_order[0]
must be nil
, so your array must be empty. You may also add simple puts messages, for example:
puts "a1_order: #{a1_order}"
puts "a2_order: #{a2_order}"
a_total = a1_order.reverse[0].length - a2_order[0].length
b_total = a2_order.reverse[0].length - a1_order[0].length
Now when running your program, you can inspect your sorted arrays and it should be quite clear that you're trying to call methods on nil
s.
Now, having that covered, we can try to make your program a bit nicer. First of all, as I mentioned, your first check doesn't make much sense. Let's turn it into:
return -1 if [a1,a2].any?(&:empty)
which will actually return from your method with -1
if any of arrays are empty.
Going further:
a1_order = a1.sort{|left, right| left.length <=> right.length}
can be written as:
a1_order.sort_by(&:length)
Calling
a1_order.reverse[0]
is a bit inefficient, as it will create a copy of your array with a reversed order, you may simply do a1_order.last
instead.
If looking for maximum/minimum values, you may use Enumerable#max_by / Enumerable#min_by like so:
a_total = a1.max_by(&:length).length - a2.min_by(&:length).length
b_total = a2.max_by(&:length).length - a1.min_by(&:length).length
And getting a higher value can be achieved with Array#max:
[a_total, b_total].max
Wrapping this all together, your method may look like this:
def mxdiflg(a1, a2)
return -1 if [a1, a2].any?(&:empty?)
a_total = a1.max_by(&:length).length - a2.min_by(&:length).length
b_total = a2.max_by(&:length).length - a1.min_by(&:length).length
[a_total, b_total].max
end