1

So I thought I understood this, but I'm not getting the output I expected, so obviously I don't understand it.

In Ruby (2.0.0)

a = [1,2,3,4]
a.each do |e|
    a.delete(e)
end
a = [2,4]

It doesn't seem to be looping through each item in the array. However, when I simply output the item, it loops through each item. There's some mechanism of a.delete(e) that is affecting the iteration.

a = [1,2,3,4]
a.each do |e|
    puts e
end
=> 1
=> 2
=> 3
=> 4

Ultimately, I want to put a conditional into the loop, such as:

a = [1,2,3,4]
a.each do |e|
    if e < 3
        a.delete(e)
    end
end

How can I get this loop it iterate through each item and delete it? Thank you!

5
  • What is your question? Commented Apr 16, 2014 at 15:48
  • Clarified the question. Commented Apr 16, 2014 at 15:50
  • 2
    In future, consider holding off for awhile before choosing an answer. A quick choice (here, a mere 15 minutes after posting!) may discourage other, possibly better, answers, and, imo, is not respectful to those still preparing answers. Commented Apr 16, 2014 at 16:05
  • Thanks for the beta. I've unselected the answer and will give it some time before re-accepting. Commented Apr 16, 2014 at 16:08
  • 2
    My comment has nothing to do with with @sawa's answer, which I think is quite good, and got a vote from me. Commented Apr 16, 2014 at 16:10

2 Answers 2

6

DO NOT mutate a collection when you iterate over it, unless you know what you are doing.

For your ultimate purpose,

a = [1,2,3,4]
a.reject!{|e| e < 3 }
Sign up to request clarification or add additional context in comments.

3 Comments

I would even say not even if you know what you're doing. It wouldn't make for very readable code, especially when ruby has lovely methods like reject! and select!, like you mentioned.
@PaulRichter Yes, I agree with you. That's bug prone and rely heavily on the implementation details.
I think JRuby will throw a java.util.ConcurrentModificationException in this case. At least with Array and Hash which are actually backed by Java collections in JRuby.
4

With

a = [1,2,3,4]
a.each do |e|
  a.delete(e)
end
a # => [2, 4]

The first iteration was at index 0 with e being 1. That being deleted, a becomes [2,3,4] and the next iteration is at index 1, with e being 3. That being deleted, a becomes [2,4]. The next iteration would be at index 2, but since a is not that long anymore, it stops, returning a's value as [2, 4].

In order to iterate through each item and delete it, given that there is no duplicate, a common way is to iterate backwards.

a = [1,2,3,4]
a.reverse_each do |e|
  a.delete(e)
end
a # => []

a = [1,2,3,4]
a.reverse_each do |e|
  if e < 3
    a.delete(e)
  end
end
a # => [3, 4]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.