OK to delete hash pairs while iterating through it?

Discussion in 'Perl Misc' started by Jerry Krinock, Sep 9, 2008.

  1. In at least one other language, I read that it is not safe to delete
    array or dictionary elements while iterating through it. Obviously,
    this could cause trouble. Is this safe to do with a hash in perl?

    Example: The following sub works OK, but is it guaranteed safe?

    sub removeEmptyStringValuesFromHashRef {
    my $hashRef = shift ;
    while (my ($key, $value) = each(%$hashRef)) {
    if (defined($value)) {
    if (length($value) == 0) {
    delete ($hashRef->{$key}) ;
    }
    }
    }
    }
    Jerry Krinock, Sep 9, 2008
    #1
    1. Advertising

  2. Jerry Krinock <> writes:

    > In at least one other language, I read that it is not safe to delete
    > array or dictionary elements while iterating through it. Obviously,
    > this could cause trouble. Is this safe to do with a hash in perl?


    The documentation for the each function says:

    If you add or delete elements of a hash while you're iterating over
    it, you may get entries skipped or duplicated, so don't. Exception:
    It is always safe to delete the item most recently returned by
    "each()", which means that the following code will work:

    [code example snipped]

    The exception should answer you question.

    //Makholm
    Peter Makholm, Sep 9, 2008
    #2
    1. Advertising

  3. Jerry Krinock <> writes:

    > In at least one other language, I read that it is not safe to delete
    > array or dictionary elements while iterating through it. Obviously,
    > this could cause trouble. Is this safe to do with a hash in perl?
    >
    > Example: The following sub works OK, but is it guaranteed safe?
    >
    > sub removeEmptyStringValuesFromHashRef {
    > my $hashRef = shift ;
    > while (my ($key, $value) = each(%$hashRef)) {
    > if (defined($value)) {
    > if (length($value) == 0) {
    > delete ($hashRef->{$key}) ;
    > }
    > }
    > }
    > }


    from "perldoc -f each":

    If you add or delete elements of a hash while you’re iterating over it,
    you may get entries skipped or duplicated, so don’t. Exception: It is
    always safe to delete the item most recently returned by "each()",
    which means that the following code will work:

    while (($key, $value) = each %hash) {
    print $key, "\n";
    delete $hash{$key}; # This is safe
    }


    --
    Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
    Joost Diepenmaat, Sep 9, 2008
    #3
  4. Jerry Krinock

    Guest

    Peter Makholm <> wrote:
    > Jerry Krinock <> writes:
    >
    > > In at least one other language, I read that it is not safe to delete
    > > array or dictionary elements while iterating through it. Obviously,
    > > this could cause trouble. Is this safe to do with a hash in perl?

    >
    > The documentation for the each function says:
    >
    > If you add or delete elements of a hash while you're iterating over
    > it, you may get entries skipped or duplicated, so don't. Exception:
    > It is always safe to delete the item most recently returned by
    > "each()", which means that the following code will work:
    >
    > [code example snipped]
    >
    > The exception should answer you question.


    From a previous discussion here, it seems the documentation is wrong, but
    not in a way that affects the OP. It is safe to delete any item, including
    the one just returned.

    Making it safe to delete the one just returned required a special case in
    the hash code guts, while deleting anything else is "naturally" safe.

    Adding, on the other hand, is something best avoided.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    The costs of publication of this article were defrayed in part by the
    payment of page charges. This article must therefore be hereby marked
    advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
    this fact.
    , Sep 9, 2008
    #4
  5. wrote:
    *SKIP*
    > Making it safe to delete the one just returned required a special case
    > in the hash code guts, while deleting anything else is "naturally"
    > safe. Adding, on the other hand, is something best avoided.


    (Just opening one more DGBI war)

    First I picked that:

    perl -wle '
    %x = qw(a b c d e f);
    $z = 0;
    while($y = each %x) {
    print "$y => $x{$y}";
    $x{$z++} = $z++ if $z < 10; }
    '
    e => f
    1 => 0
    c => d
    a => b
    3 => 2
    7 => 6
    9 => 8
    5 => 4

    I don't know what's going on here. The second, I believe, should be
    more clear:

    perl -wle '
    %x = qw(a b c d e f);
    %y = qw(z y x w v u);
    while($z = each %x) {
    print "$z => $x{$z}";
    $z = each %y;
    defined $z or next;
    $x{$z} = $y{$z}; }
    '
    e => f
    c => d
    a => b
    x => w
    v => u
    z => y

    What surprises me most, is key-messing in first case, which doesn't show
    in second.

    --
    Torvalds' goal for Linux is very simple: World Domination
    Eric Pozharski, Sep 11, 2008
    #5
  6. Jerry Krinock

    Guest

    Eric Pozharski <> wrote:
    > wrote:
    > *SKIP*
    > > Making it safe to delete the one just returned required a special case
    > > in the hash code guts, while deleting anything else is "naturally"
    > > safe. Adding, on the other hand, is something best avoided.

    >
    > (Just opening one more DGBI war)


    What's a DGBI war?

    >
    > First I picked that:
    >
    > perl -wle '
    > %x = qw(a b c d e f);
    > $z = 0;
    > while($y = each %x) {
    > print "$y => $x{$y}";
    > $x{$z++} = $z++ if $z < 10; }
    > '
    > e => f
    > 1 => 0
    > c => d
    > a => b
    > 3 => 2
    > 7 => 6
    > 9 => 8
    > 5 => 4
    >
    > I don't know what's going on here.


    I don't know what part you don't know. Could you be more specific.


    > The second, I believe, should be
    > more clear:


    And I don't *what* you think will be made clear.
    >
    > perl -wle '
    > %x = qw(a b c d e f);
    > %y = qw(z y x w v u);
    > while($z = each %x) {
    > print "$z => $x{$z}";
    > $z = each %y;
    > defined $z or next;
    > $x{$z} = $y{$z}; }


    Here, the value of $x{$z} is changed, but no *keys* are added or deleted
    from %x while it is being iterated over by each.


    > '
    > e => f
    > c => d
    > a => b
    > x => w
    > v => u
    > z => y
    >
    > What surprises me most, is key-messing in first case, which doesn't show
    > in second.


    Which key do you consider to be missing? Adding to a hash can give
    "weird" results, but your first example doesn't illustrate that in any way.

    Are you confusing yourself with the increment operator and order of
    execution? Sorry, I just don't see what you are seeing in that data.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    The costs of publication of this article were defrayed in part by the
    payment of page charges. This article must therefore be hereby marked
    advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
    this fact.
    , Sep 12, 2008
    #6
  7. Jerry Krinock

    Guest

    wrote:
    > Eric Pozharski <> wrote:
    > > perl -wle '
    > > %x = qw(a b c d e f);
    > > %y = qw(z y x w v u);
    > > while($z = each %x) {
    > > print "$z => $x{$z}";
    > > $z = each %y;
    > > defined $z or next;
    > > $x{$z} = $y{$z}; }

    >
    > Here, the value of $x{$z} is changed, but no *keys* are added or deleted
    > from %x while it is being iterated over by each.


    No, I misinterpreted that. Yes, keys are being added to %x.


    >
    > > '
    > > e => f
    > > c => d
    > > a => b
    > > x => w
    > > v => u
    > > z => y


    But what conclusion are you drawing from this?

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    The costs of publication of this article were defrayed in part by the
    payment of page charges. This article must therefore be hereby marked
    advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
    this fact.
    , Sep 12, 2008
    #7
  8. wrote:
    *SKIP*
    > But what conclusion are you drawing from this?


    The first conclusion is that someone makes too much noise. The second
    is that someone has to use bigger samples if he wants meaningful
    results. That (below) clearly shows that adding keys while iterating
    hash is unsafe.

    perl -wle '
    foreach(0 .. 25) {
    $x{sprintf q|x%02i|, $_} = 1;
    $y{sprintf q|y%02i|, $_} = 1; };
    print scalar %x;
    print scalar %y;
    $m = 0;
    while($z = each %x) {
    print "$z => ", $m++;
    $z = each %y;
    defined $z or next;
    $x{$z} = $y{$z}; }
    ' |sort
    18/32
    19/32
    x00 => 30
    x01 => 1
    x02 => 0
    x02 => 20
    x03 => 9
    x04 => 37
    x05 => 12
    x06 => 27
    x07 => 5
    x08 => 16
    x09 => 18
    x10 => 8
    x11 => 23
    x12 => 33
    x13 => 7
    x14 => 42
    x15 => 21
    x15 => 3
    x16 => 14
    x17 => 36
    x18 => 11
    x19 => 2
    x20 => 13
    x21 => 19
    x22 => 10
    x23 => 15
    x24 => 28
    x25 => 17
    y02 => 26
    y03 => 29
    y04 => 34
    y06 => 38
    y07 => 40
    y09 => 31
    y10 => 39
    y11 => 24
    y12 => 22
    y13 => 6
    y17 => 25
    y18 => 35
    y21 => 41
    y22 => 43
    y23 => 4
    y24 => 32

    p.s. Do bigger samples mean bigger noise?

    --
    Torvalds' goal for Linux is very simple: World Domination
    Eric Pozharski, Sep 12, 2008
    #8
    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. rp
    Replies:
    1
    Views:
    511
    red floyd
    Nov 10, 2011
  2. Depili
    Replies:
    5
    Views:
    134
    David Vallner
    Jan 13, 2006
  3. Thaddeus L Olczyk

    Iterating over an area in pairs.

    Thaddeus L Olczyk, May 6, 2006, in forum: Ruby
    Replies:
    7
    Views:
    172
    Ross Bamford
    May 9, 2006
  4. FireAphis

    Iterating list in pairs

    FireAphis, Aug 8, 2007, in forum: Ruby
    Replies:
    12
    Views:
    190
    FireAphis
    Aug 9, 2007
  5. Tarscher
    Replies:
    4
    Views:
    242
    Robert Klemme
    Mar 25, 2009
Loading...

Share This Page