# Array#each Looping Gotcha

**URL:** <https://www.ruby-forum.com/t/array-each-looping-gotcha/58253>\
**Category:** Ruby\
**Created:** [April 20, 2006, 12:43am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253 "2006-04-20T00:43:42Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 12:43am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/1 "2006-04-20T00:43:42Z")

</div>

I think I’ve found a gotcha. Really, it should be expected behavior, but  
it wasn’t immediately obvious to me, so I thought it’s at least worth  
mentioning.

Let’s say you want to iterate through an array and delete any items in  
that array that match a certain criteria. I thought it’d make sense to  
do this:

items.each do |x|  
if x == “”  
items.delete(x)  
end  
end

If items.each referred to items[] by reference, this would make sense.  
But since it references by value, you’re literally changing the array  
live, as you’re iterating through it. This means that, if you delete an  
item in mid-iteration, you change the index of items[]. Since you  
deleted something, you skip the next item.

1. Do I have this right?

2. Am I right in assuming that it’s possible to create an infinite loop  
this way by continually push()ing things on to items[]?

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 1:00am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/2 "2006-04-20T01:00:48Z")

</div>

On 4/19/06, Nathan O. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> items.delete(x)
> 
> ```
> 
> 1. Do I have this right?
> 
> 2. Am I right in assuming that it’s possible to create an infinite loop  
> this way by continually push()ing things on to items[]?

Except the reference/value thing.

Look at Array#delete\_if for your specific example.

-austin

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 1:03am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/3 "2006-04-20T01:03:56Z")

</div>

Hi,

In message “Re: Array#each Looping Gotcha”  
on Thu, 20 Apr 2006 07:43:46 +0900, Nathan O.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

|items.each do |x|  
| if x == “”  
| items.delete(x)  
| end  
|end  
|  
|  
|If items.each referred to items[] by reference, this would make sense.  
|But since it references by value, you’re literally changing the array  
|live, as you’re iterating through it. This means that, if you delete an  
|item in mid-iteration, you change the index of items[]. Since you  
|deleted something, you skip the next item.  
|  
|1) Do I have this right?

I’m not sure what you mean by the word “right” here. It’s ok for you  
to write that kind of program, but I don’t (can’t) guarantee you will  
get what you expect, although I try my best. It might cost you much  
to guarantee loop safety. It shouldn’t crash in any case though.

|2) Am I right in assuming that it’s possible to create an infinite loop  
|this way by continually push()ing things on to items[]?

Yes, Ruby obeys you if you command it to loop infinitely.

```
						matz.

```

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 1:17am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/4 "2006-04-20T01:17:30Z")

</div>

Yukihiro M. wrote:

> I’m not sure what you mean by the word “right” here. It’s ok for you  
> to write that kind of program, but I don’t (can’t) guarantee you will  
> get what you expect, although I try my best. It might cost you much  
> to guarantee loop safety. It shouldn’t crash in any case though.

Though I was confused for half of the day today, I have to admit that  
the current implementation is probably for the best. Where this:

arr.each do |x|  
if y; arr.delete(x); end  
end

Can be made to work the way I personally thought it would, it’s much  
safer to do something like this:

delete\_list = []  
arr.each do |x|  
if y; delete\_list.push(x); end  
end  
arr -= delete\_list

Or better yet, since Ruby includes the feature, use Array#delete\_if.

> Yes, Ruby obeys you if you command it to loop infinitely.

I was more asking if that’s what would happen, but I suppose the wording  
of my question made its own answer 🙂

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 4:19am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/5 "2006-04-20T04:19:31Z")

</div>

Hi –

On Thu, 20 Apr 2006, Nathan O. wrote:

> if y; arr.delete(x); end
> 
> Or better yet, since Ruby includes the feature, use Array#delete\_if.

Also, don’t forget (among reasons deleting from an array during an  
iteration is bad) that delete deletes all instances:

irb(main):027:0\> a = [1,2,3,1,4,5,1,6,7]  
=\> [1, 2, 3, 1, 4, 5, 1, 6, 7]  
irb(main):028:0\> a.delete(1)  
=\> 1  
irb(main):029:0\> a  
=\> [2, 3, 4, 5, 6, 7] # all the 1’s deleted

Also, something like each\_with\_index would probably cease to make  
sense…

David

–  
David A. Black (removed\_email\_address@domain.invalid)  
Ruby Power and Light, LLC ([http://www.rubypowerandlight.com](http://www.rubypowerandlight.com))

“Ruby for Rails” PDF now on sale! [Ruby for Rails](http://www.manning.com/black)  
Paper version coming in early May!

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 11:00am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/6 "2006-04-20T11:00:46Z")

</div>

> items.each do |x|  
> if x == “”  
> items.delete(x)  
> end  
> end  
> Wow, in Java you this would throw ConcurrentModificationException (i.e.  
> you can not iterate and modify a list at the same time, says Java) -  
> AFAIK, in java there is no workaround for this. It is interesting that  
> Ruby handles this as well, although i am not sure to which extent this  
> is (black) magic 😉

Cheers,  
Peter

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 11:28am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/7 "2006-04-20T11:28:36Z")

</div>

2006/4/20, Peter S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> > items.each do |x|  
> > if x == “”  
> > items.delete(x)  
> > end  
> > end  
> > Wow, in Java you this would throw ConcurrentModificationException (i.e.  
> > you can not iterate and modify a list at the same time, says Java) -  
> > AFAIK, in java there is no workaround for this.

Not exactly true. This special scenario is well covered by Java:

> **[JDK 20 Documentation - Home](https://docs.oracle.com/en/java/javase/20/)**
>
> The documentation for JDK 20 includes developer guides, API documentation, and release notes.

Std. collections all support remove().

IMHO iterating and deleting like shown is a very bad idea. Since  
there is a method for doing deletions that’s exactly the way to go.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![nko](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/91b2a8/32.png) [@nko](https://www.ruby-forum.com/u/nko)\
**Post date:** [April 20, 2006, 11:44am UTC](https://www.ruby-forum.com/t/array-each-looping-gotcha/58253/8 "2006-04-20T11:44:12Z")

</div>

Robert K. wrote:

> 2006/4/20, Peter S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > > items.each do |x|  
> > > if x == “”  
> > > items.delete(x)  
> > > end  
> > > end  
> > > Not exactly true. This special scenario is well covered by Java:  
> > > I stand corrected. I had so many problems with similar  
> > > iterate-but-dont-touch scenarios in J that i threw remove() in the same  
> > > bag automatically ;-).

Anyway, i agree that iterating and deleting is not a good idea…

Cheers,  
Peter
