Issues using array.delete within a loop of the same array

Discussion in 'Ruby' started by james.d.masters@gmail.com, Mar 16, 2007.

  1. Guest

    This is a simplified example for what I'm trying to do but gets the
    point across:

    irb(main):001:0> a = [1,2,3,4,5]
    => [1, 2, 3, 4, 5]
    irb(main):002:0> a.each {|e| a.delete e}
    => [2, 4]

    I would expect the array to be emptied. Insight please...

    Yes, I know that there are other ways to empty an array (i.e. a =
    []). My code is more complex and I'm more interested in why this is
    happening and if there is a work-around for removing array items while
    iterating over the same array. There will be other cases in this code
    where I will only want to remove some of the items.

    Thanks in advance...
    , Mar 16, 2007
    #1
    1. Advertising

  2. wrote:
    > This is a simplified example for what I'm trying to do but gets the
    > point across:
    >
    > irb(main):001:0> a = [1,2,3,4,5]
    > => [1, 2, 3, 4, 5]
    > irb(main):002:0> a.each {|e| a.delete e}
    > => [2, 4]
    >
    > I would expect the array to be emptied. Insight please...
    >
    > Yes, I know that there are other ways to empty an array (i.e. a =
    > []). My code is more complex and I'm more interested in why this is
    > happening and if there is a work-around for removing array items while
    > iterating over the same array. There will be other cases in this code
    > where I will only want to remove some of the items.
    >
    > Thanks in advance...
    >
    >
    >

    Use #delete_if instead.
    Timothy Hunter, Mar 16, 2007
    #2
    1. Advertising

  3. MenTaLguY Guest

    On Sat, 17 Mar 2007 05:45:05 +0900, wrote:
    > Yes, I know that there are other ways to empty an array (i.e. a =
    > []).


    a = [] creates a new, empty array; it does not empty the existing array.

    > My code is more complex and I'm more interested in why this is
    > happening


    It's disallowed by design -- removing elements in the midst of iteration would be a bit like trying to remove carpet tiles while you are standing on them.

    > and if there is a work-around for removing array items while
    > iterating over the same array.


    Have you considered using Array#reject! to iterate over the array? You can use the result of the block for each iteration (true or false) to control whether each element is dropped or retained once the iteration completes.

    a.reject! { |e|
    # ... do stuff
    e > 3 # discard elements greater than three
    }

    -mental
    MenTaLguY, Mar 16, 2007
    #3
  4. Guest

    On Mar 16, 2:01 pm, Timothy Hunter <> wrote:
    > Use #delete_if instead.


    Thanks - I tried that and it also did not work. Sorry for not posting
    this attempt in my original:

    irb(main):001:0> a = [1,2,3,4,5]
    => [1, 2, 3, 4, 5]
    irb(main):002:0> a.each {|e| a.delete_if {|e2| e2 == e}}
    => [2, 4]
    , Mar 16, 2007
    #4
  5. Guest

    On Mar 16, 2:02 pm, MenTaLguY <> wrote:
    > a = [] creates a new, empty array; it does not empty the existing array.


    Yup, good point.

    > It's disallowed by design -- removing elements in the midst of iteration would be a bit like trying to remove carpet tiles while you are standing on them.


    OK, I'll take that... I had a feeling that would be the final answer.
    Although I can't see why it wouldn't be feasible in a language -
    especially as I'm removing the current item of iteration (i.e. not one
    further down the list) and when there are no duplicates of the same
    object in the array.

    > Have you considered using Array#reject! to iterate over the array? You can use the result of the block for each iteration (true or false) to control whether each element is dropped or retained once the iteration completes.


    I vaguely remember reading about Array#reject! but haven't used it
    much - I'll have to give that a shot. Thanks...
    , Mar 16, 2007
    #5
  6. Phrogz Guest

    On Mar 16, 4:00 pm, wrote:
    > On Mar 16, 2:01 pm, Timothy Hunter <> wrote:
    >
    > > Use #delete_if instead.

    >
    > Thanks - I tried that and it also did not work. Sorry for not posting
    > this attempt in my original:
    >
    > irb(main):001:0> a = [1,2,3,4,5]
    > => [1, 2, 3, 4, 5]
    > irb(main):002:0> a.each {|e| a.delete_if {|e2| e2 == e}}
    > => [2, 4]


    Kindly suggest that you RTFM by typing "ri Array#delete_if" into your
    console. :)

    If that doesn't make it clear, try this:

    a.delete_if{ true }
    Phrogz, Mar 16, 2007
    #6
  7. wrote:
    > On Mar 16, 2:01 pm, Timothy Hunter <> wrote:
    >
    >> Use #delete_if instead.
    >>

    >
    > Thanks - I tried that and it also did not work. Sorry for not posting
    > this attempt in my original:
    >
    > irb(main):001:0> a = [1,2,3,4,5]
    > => [1, 2, 3, 4, 5]
    > irb(main):002:0> a.each {|e| a.delete_if {|e2| e2 == e}}
    > => [2, 4]
    >
    >
    >

    #delete_if itself iterates over the array elements. You don't need to
    use #each at all.

    $ irb
    irb(main):001:0> a = [0,1,2,3,4,5]
    => [0, 1, 2, 3, 4, 5]
    irb(main):002:0> a.delete_if {|e| e %2 == 0}
    => [1, 3, 5]
    irb(main):003:0>
    Timothy Hunter, Mar 16, 2007
    #7
  8. Phrogz Guest

    On Mar 16, 2:42 pm, wrote:
    > This is a simplified example for what I'm trying to do but gets the
    > point across:
    >
    > irb(main):001:0> a = [1,2,3,4,5]
    > => [1, 2, 3, 4, 5]
    > irb(main):002:0> a.each {|e| a.delete e}
    > => [2, 4]


    a = [1,2,3,4,5]
    (a.length-1).downto(0){ |i|
    a.delete_at( i )
    }
    p a
    #=> []
    Phrogz, Mar 16, 2007
    #8
  9. Robert Dober Guest

    On 3/16/07, Phrogz <> wrote:
    > On Mar 16, 4:00 pm, wrote:
    > > On Mar 16, 2:01 pm, Timothy Hunter <> wrote:
    > >
    > > > Use #delete_if instead.

    > >
    > > Thanks - I tried that and it also did not work. Sorry for not posting
    > > this attempt in my original:
    > >
    > > irb(main):001:0> a = [1,2,3,4,5]
    > > => [1, 2, 3, 4, 5]
    > > irb(main):002:0> a.each {|e| a.delete_if {|e2| e2 == e}}
    > > => [2, 4]

    >
    > Kindly suggest that you RTFM by typing "ri Array#delete_if" into your
    > console. :)
    >
    > If that doesn't make it clear, try this:
    >
    > a.delete_if{ true }

    This is a nice alias for a.clear ;)
    Robert
    >
    >
    >
    >



    --
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Mar 16, 2007
    #9
  10. Robert Dober Guest

    On 3/16/07, Fedor Labounko <> wrote:
    > Now this is pure speculation on my part and I'm not offering a solution to
    > the problem, rather a likely explanation. The other solutions all look good
    > to me as alternatives.
    >
    > It would make sense that what Array#each is doing behind the scenes is
    > simply using an index and a for loop up to the size of the array, and then
    > passing you a. So then during the first step you delete a[0], which
    > renumbers the elements in the array. During the second step you delete a[1],
    > which is now actually 3, since that's now the second element in the array.
    > Continue in this manner you'll skip every other element in the array.

    Let us see

    VALUE
    rb_ary_each(ary)
    VALUE ary;
    {
    long i;

    for (i=0; i<RARRAY(ary)->len; i++) {
    rb_yield(RARRAY(ary)->ptr);
    }
    return ary;
    }

    your speculation was correct :) fortuntely i < RARRAY(ary)-> len is
    reavaluated after each yield!

    Cheers
    Robert
    >

    <snip>


    --
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Mar 16, 2007
    #10
  11. Guest

    On Mar 16, 3:08 pm, "Phrogz" <> wrote:
    > Kindly suggest that you RTFM by typing "ri Array#delete_if" into your
    > console. :)


    I did RTFM before posting. The question in my original posting was
    related to the behavior of deleting items from a list during iteration
    so that's why I posted Array#delete_if within the context of
    Array#each. To use Array#delete_if outside of the iteration does the
    job yet the original question remained. I think that the answer is
    that deleting from the same array during an iteration is a no-no using
    Array#each... I'm OK with that. I'll use Array#delete_if or
    Array.reject!

    Thanks...
    , Mar 16, 2007
    #11
  12. Gary Wright Guest

    On Mar 16, 2007, at 5:02 PM, MenTaLguY wrote:
    > It's disallowed by design -- removing elements in the midst of
    > iteration would be a bit like trying to remove carpet tiles while
    > you are standing on them.


    Maybe better to say that the behavior is implementation
    dependent and therefore should be avoided.

    The word "disallow" implies that it is syntactically
    invalid or that it will raise an exception yet, as was
    shown by other posters, neither occurs.

    Gary Wright
    Gary Wright, Mar 16, 2007
    #12
  13. Robert Dober Guest

    On 3/16/07, <> wrote:
    > On Mar 16, 3:08 pm, "Phrogz" <> wrote:
    > > Kindly suggest that you RTFM by typing "ri Array#delete_if" into your
    > > console. :)

    >
    > I did RTFM before posting. The question in my original posting was
    > related to the behavior of deleting items from a list during iteration
    > so that's why I posted Array#delete_if within the context of
    > Array#each. To use Array#delete_if outside of the iteration does the
    > job yet the original question remained. I think that the answer is
    > that deleting from the same array during an iteration is a no-no using
    > Array#each... I'm OK with that. I'll use Array#delete_if or
    > Array.reject!
    >
    > Thanks...
    >


    The code I posted was version 1.8.5 p12, and of course I should have
    added that the behavior is not defined.
    YARV does exactly the same right now though.

    Good to point it out clearly.

    Cheers
    Robert
    >
    >
    >



    --
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Mar 16, 2007
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    387
    =?ISO-8859-1?Q?G=F6ran_Andersson?=
    May 4, 2006
  2. takayuki
    Replies:
    2
    Views:
    261
    Calvin Spealman
    Jun 16, 2008
  3. takayuki
    Replies:
    17
    Views:
    459
    John Salerno
    Jun 17, 2008
  4. addi
    Replies:
    0
    Views:
    255
  5. Isaac Won
    Replies:
    9
    Views:
    342
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page