Reputation: 2832
I am having trouble understanding the following code:
vowels_arr = ["a","e","i","o","u"]
(0...(vowels_arr.length - 1)).all? {|i| vowels_arr[i] <= vowels_arr[i + 1]}
When I try to run it WITHOUT the - 1, I get an error saying that I can't compare a string to nil. But what I dont understand is that why do we even need the -1?? The "..." ranger makes it so we are only evaluating "a","e","i","o" (4 out of the 5). Since the total length is 5 and we are already at 4 things to compare, my belief is that the comparison (vowels_arr[i] <= vowels_arr [i+1]) should work without the -1.
Can someone please explain to me why we need the -1 after array length?
Also are there other ways in ruby to get past this comparing to nil error?
Upvotes: 0
Views: 356
Reputation: 168081
As Sergio answers, the problem is with vowels_arr[i + 1]
. The variable i
ranges over the indices of vowels_arr
, and hence i + 1
will not necessarily point to an existing index of vowels_arr
. Particularly, when i
reaches the last index, i + 1
will be greater than the existing indices, and vowels_arr[i + 1]
will be nil
.
Also as Sergio answers, if your purpose is to see if it is sorted, then doing as Sergio's answer is straightforward, but in general cases, you can do it like this:
vowels_arr.each_cons(2).all?{|e1, e2| e1 <= e2}
Upvotes: 1
Reputation: 230286
It's because of this:
vowels_arr[i + 1]
(0...(vowels_arr.length))
will return all indexes for the array.
(0...(vowels_arr.length)).to_a # => [0, 1, 2, 3, 4]
But then you're trying to get next index from current. If current index is last index (4), this results in an error, because you get nil
where you expect a string (because element doesn't exist at non-existent index). That's why you need length - 1
, to allow your logic not to go out of array's bounds.
By the way, if you're trying to check if the array is sorted, why not do it more directly?
vowels_arr = ["a","e","i","o","u"]
puts vowels_arr.sort == vowels_arr
# >> true
Upvotes: 2
Reputation: 118261
vowels_arr = ["a","e","i","o","u"]
p vowels_arr[vowels_arr.length] #=> nil
(0..(vowels_arr.length)).all? {|i| vowels_arr[i] <= vowels_arr[i + 1]}
#=> `<=': comparison of String with nil failed (ArgumentError)
As you are passing the vowels_arr[vowels_arr.length]
element to the block,which is nil
. In Ruby
array's are 0(zero)
based. Thus vowels_arr.length
gives 5
means elements are in the range of (0..4)
. see below:
vowels_arr = ["a","e","i","o","u"]
p vowels_arr[0] #=> "a"
p vowels_arr[1] #=> "e"
p vowels_arr[2] #=> "i"
p vowels_arr[3] #=> "o"
p vowels_arr[4] #=> "u"
p vowels_arr[5] #=> nil
p vowels_arr[6] #=> nil
(0..(vowels_arr.length))
means you are passing to the block 0,1,2,3,4,5
, and an attempt to access 5
gives nil
, as in your array in 5th
index is nil
. See why the code (0...(vowels_arr.length)).all? {|i| vowels_arr[i] <= vowels_arr[i + 1]}
failed by the below debugging with each
to see what has been passed to the block:
vowels_arr = ["a","e","i","o","u"]
(0...(vowels_arr.length)).each {|i| p vowels_arr[i],"--",vowels_arr[i+1]}
p (1...3).to_a
Output:
"a"
"--"
"e"
"e"
"--"
"i"
"i"
"--"
"o"
"o"
"--"
"u"
"u"
"--"
nil
Upvotes: -1