# Mysterious behavior with loops

**URL:** <https://rubytalk.org/t/mysterious-behavior-with-loops/46788>\
**Category:** ruby-talk\
**Created:** [29 May 2008 17:00 UTC](https://rubytalk.org/t/mysterious-behavior-with-loops/46788 "2008-05-29T17:00:12Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Eric\_LIn](https://avatars.discourse-cdn.com/v4/letter/e/45deac/32.png) [@Eric\_LIn](https://rubytalk.org/u/Eric_LIn)\
**Post date:** [29 May 2008 17:00 UTC](https://rubytalk.org/t/mysterious-behavior-with-loops/46788/1 "2008-05-29T17:00:12Z")

</div>

Enter these in irb:

a = [1,2,3]

a.each do |i|  
&nbsp;&nbsp;a.delete(i)  
end

Result?

a =\> [2]

Shouldn't a be [] ?

Eric

---

<div class="post-metadata">

**Author:** ![Stefano\_Crocco](https://avatars.discourse-cdn.com/v4/letter/s/5f9b8f/32.png) [@Stefano\_Crocco](https://rubytalk.org/u/Stefano_Crocco)\
**Post date:** [29 May 2008 17:16 UTC](https://rubytalk.org/t/mysterious-behavior-with-loops/46788/2 "2008-05-29T17:16:40Z")

</div>

Iterating on an array while deleting elements from it is usually a bad idea,  
because items may be skipped, as it happens in your case. In particular, this  
is the C code for Array#each:

VALUE  
rb\_ary\_each(ary)  
VALUE ary;  
{  
&nbsp;&nbsp;long i;  
&nbsp;&nbsp;for (i=0; i\<RARRAY(ary)-\>len; i++) {  
&nbsp;&nbsp;&nbsp;&nbsp;rb\_yield(RARRAY(ary)-\>ptr[i]);  
&nbsp;&nbsp;}  
&nbsp;&nbsp;return ary;  
}

If you don't understand C code, this is what it means: for all the numbers  
from 0 to the number of elements in the array (excluded), take the element of  
the array with that index and pass it to the block.

Now, look what happens for the first element of the array. The index is 0,  
corresponding to the element 1. The element is passed to the block, which  
deletes it. Now, the array contains only two elements: 2 and 3, with 2  
corresponding to the index 0 and 3 to the index 1. But the index used by each  
to iterate on the array elements is increased to 1 (since Array#each can't  
know that you deleted an item). This means that the next element which will be  
passed to the block will be the one corresponding to index 1, which is 3. This  
means that one item won't be passed to the block and won't be deleted.

If you want to delete all items of the arryay, you can simply use the delete  
method. If you want to delete only some items, you can use Array#delete\_if,  
which takes a block and removes from the array all the elements for which the  
block returns true.

I hope this helps

Stefano

> **···**
>
> On Thursday 29 May 2008, ericlin852@gmail.com wrote:
> 
> > Enter these in irb:
> > 
> > a = [1,2,3]
> > 
> > a.each do |i|  
> > &nbsp;&nbsp;a.delete(i)  
> > end
> > 
> > Result?
> > 
> > a =\> [2]
> > 
> > Shouldn't a be ?
> > 
> > Eric

---

<div class="post-metadata">

**Author:** ![Eric\_LIn](https://avatars.discourse-cdn.com/v4/letter/e/45deac/32.png) [@Eric\_LIn](https://rubytalk.org/u/Eric_LIn)\
**Post date:** [29 May 2008 18:34 UTC](https://rubytalk.org/t/mysterious-behavior-with-loops/46788/3 "2008-05-29T18:34:59Z")

</div>

Thanks Stefano, that definitely answered my question. It's quite  
obvious when the index variable is made explicit.

Eric

> **···**
>
> On May 29, 10:16 am, Stefano Crocco \<stefano.cro...@alice.it\> wrote:
> 
> > On Thursday 29 May 2008, ericlin...@gmail.com wrote:
> > 
> > \> Enter these in irb:
> > 
> > \> a = [1,2,3]
> > 
> > \> a.each do |i|  
> > \> a.delete(i)  
> > \> end
> > 
> > \> Result?
> > 
> > \> a =\> [2]
> > 
> > \> Shouldn't a be ?
> > 
> > \> Eric
> > 
> > Iterating on an array while deleting elements from it is usually a bad idea,  
> > because items may be skipped, as it happens in your case. In particular, this  
> > is the C code for Array#each:
> > 
> > VALUE  
> > rb\_ary\_each(ary)  
> > VALUE ary;  
> > {  
> > long i;  
> > for (i=0; i\<RARRAY(ary)-\>len; i++) {  
> > rb\_yield(RARRAY(ary)-\>ptr[i]);  
> > }  
> > return ary;
> > 
> > }
> > 
> > If you don't understand C code, this is what it means: for all the numbers  
> > from 0 to the number of elements in the array (excluded), take the element of  
> > the array with that index and pass it to the block.
> > 
> > Now, look what happens for the first element of the array. The index is 0,  
> > corresponding to the element 1. The element is passed to the block, which  
> > deletes it. Now, the array contains only two elements: 2 and 3, with 2  
> > corresponding to the index 0 and 3 to the index 1. But the index used by each  
> > to iterate on the array elements is increased to 1 (since Array#each can't  
> > know that you deleted an item). This means that the next element which will be  
> > passed to the block will be the one corresponding to index 1, which is 3. This  
> > means that one item won't be passed to the block and won't be deleted.
> > 
> > If you want to delete all items of the arryay, you can simply use the delete  
> > method. If you want to delete only some items, you can use Array#delete\_if,  
> > which takes a block and removes from the array all the elements for which the  
> > block returns true.
> > 
> > I hope this helps
> > 
> > Stefano
