I found this example in a failing test in one of my projects. Why does this work:
[[1,2,3], [2,3,4], [1,1,nil]].sort
#=> [[1, 1, nil], [1, 2, 3], [2, 3, 4]]
But this does not:
[[1,2,3], [nil,3,4], [1,1,nil]].sort
#=> ERROR: ArgumentError: comparison of Array with Array failed
Tested Ruby versions: 2.0.0
, 1.9.3
.
It's failing because it's going over the nil
. The reason the first test example doesn't fail is because the comparison of 1, 1
happens with 1, 2
. It doesn't go as far as the nil
to verify because it doesn't need to.
The example below fails because it must go over nil
initially. Try it out in irb:
[1, nil, 2].sort
ArgumentError: comparison of Fixnum with nil failed
# in this example 1,2 comes before 2,1 so no need to continue in sort
# and nil is never reached
[ [2,1,3,5], [1,2,nil,6] ].sort
=> [[1, 2, nil, 6], [2, 1, 3, 5]]
This is because of the comparison between the arrays in order to sort them, it's element to element:
In the first case [[1,2,3], [2,3,4], [1,1,nil]].sort
, the algorithm compares:
1 (of the first array) < 2 (of the second array)
1 (of the first array) = 1 (of the third array)
Then, as there are two elements equal, we have to compare the second element:
2 (of the first array) > 1 (of the third array)
Then the comparison finishes, no need to compare the 3th element.
Now, in the second case [[1,2,3], [nil,3,4], [1,1,nil]].sort
, the comparison of the first element of the arrays contains a nil, and this will raise an error.
For example, this will raise an error:
[[1,2,3], [1,nil,4], [3,1,3]].sort
This wont:
[[2,2,3], [1,nil,4], [3,1,3]].sort
This is because the #sort
method uses QSort sorting methodics, and in come cases the sort procedure reach not the last value of array. In your case [1,1,nil]
it is nil
. And it reach to nil
in case 1,nil,4
, because in last case #<=>
method returns nil
. To avoid the error, you need to redefine Array
's #<=>
method, or use complex block:
[[1,2,3], [nil,3,4], [1,1,nil]].sort do| x, y |
x <=> y || 1
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With