Reputation: 21
I am new to Ruby and I wrote a very simple application to print the days of week and then delete one day in a loop:
def print_days(days)
days.each do |day|
print "The day of the week is: #{day}\n"
days.delete(day)
print "\n*****************************************************\n"
print days
print "\n*****************************************************\n"
end
end
wd = %w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday]
print print_days(wd
This gives the following output when run. Can anyone explain me why Tuesday, Thursday and Saturday are skipped when I am deleting each element sequentially and the array shows them being there? You can run this simple code at your setup:
The day of the week is: Monday
*****************************************************
["Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Wednesday
*****************************************************
["Tuesday", "Thursday", "Friday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Friday
*****************************************************
["Tuesday", "Thursday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Sunday
*****************************************************
["Tuesday", "Thursday", "Saturday"]
*****************************************************
["Tuesday", "Thursday", "Saturday"]
Upvotes: 2
Views: 190
Reputation: 1289
Given most of the above answers explain why what you're doing is failing, you can get what you seem to want using variations of
Array#drop_while
Array#delete_if
Array#select!
or
Array#keep_if
e.g.
a=[1,2,3,4]
a.drop_while{|e| puts e; true}
Gives
1
2
3
4
=> []
Upvotes: 0
Reputation: 35520
You are deleting elements from the array while you are iterating through it, invalidating the iterator.
You could try
until (days.empty?)
day = days.shift
print "The day of the week is: #{day}\n"
end
or
days.each{|day| print "The day of the week is: #{day}\n"}
days.clear
Upvotes: 4
Reputation: 186994
You broke the cardinal rule, do not mutate the object you are iterating over, while you are iterating over it!
Here what's happeneing:
So it sort of skips deleting every other item. These types of bizarre bugs are why it's very frowned upon to change the object that you are iterating over, while you are iterating over it. Don't do that.
But given how contrived your example is, it's hard to suggest a better way. Depending on your actual goal, there is better ways to do this.
Upvotes: 2
Reputation: 2584
You are modifying the array during the iteration of all the elements. Internally the each method is keeping the index of the last item it yielded to your block. This is basically invalidating the iterator. Other languages would throw an exception for you.
Ruby does not.
So on the first time through it yields the element at index 0
Then you delete the element at index 0
Then the next time through the it yields the element at index 1, which basically skips the Tuesday since it is now at index 0.
Upvotes: 3