Reputation: 169
Given an array in Ruby:
numbers = [1, 2, 3, 4]
I'm confused about the result of what happens when modifying the array while iterating over the array:
numbers.each do |number|
p number
numbers.shift(1)
end
The output I get when running the code is 1 and 3. The 1 makes perfect sense for the first loop, but I can't seem to figure out why the program is returning a 3.
I modified the original code so I could see what is occurring at each step along the way, and included the hash marks "----" to know when each loop is finished running:
numbers = [1, 2, 3, 4]
numbers.each_with_index do |number, index|
p "Array is #{numbers} and index is #{index}"
p "Number is #{number}"
numbers.shift(1)
p "The Array after shift is now #{numbers}, number is #{number}, and the index is now #{index}"
p "----"
end
Through the first loop, shift successfully removes the 1 from the original array and the array becomes [2,3,4], while "number" is 1. But on the second loop through, instead of "number" returning 2 it returns 3.
The only way I think it makes sense is if the index itself must be determining which item to remove from the array. When the index is 0 it's removing the array item at index 0 from the array, and when the index is 1 it's removing array item at index 1 from the updated array. Then the loop stops when the index is 2 because the array no longer has an item at index 2.
This is a question as part of the Launch School course. I can't figure out why the code returns what it does. I also tried inserting binding.pry both before and after the numbers.shift(1)
is called, but it didn't seem to clarify anything to me.
Upvotes: 0
Views: 855
Reputation: 534925
numbers = [1, 2, 3, 4]
Okay, here we go with
numbers.each do |number|
# do stuff
end
First number
p number # 1, we are on the first element of [1, 2, 3, 4]
numbers.shift(1) # numbers is now [2, 3, 4]
Second number
p number # 3, we are on the second element of [2, 3, 4]
numbers.shift(1) # numbers is now [3, 4]
Third number – wait, there is no third element of [3, 4]
, we’re done.
Upvotes: 2
Reputation: 1333
do not look at it as values but rather as an address.
Enumerator(or the Iteration) follows the next address pointed by the current one.
1st loop:
1. number points to the first address (with value 1)
2. shifting array making the current 2nd address the 1st, therefore the value 2 is now on the 1st address.
2nd loop:
1. number points to the 2nd address (with value 3)
2. shifting array making the current 2nd address the 1st
3rd loop:
※same logic until 'StopIteration' is met
In regards to 'shift', it will just remove the 1st item without overthinking.
reference: https://apidock.com/ruby/Enumerator/next_values
Upvotes: 1