Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > OK to delete hash pairs while iterating through it?

Reply
Thread Tools

OK to delete hash pairs while iterating through it?

 
 
Jerry Krinock
Guest
Posts: n/a
 
      09-09-2008
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}) ;
}
}
}
}
 
Reply With Quote
 
 
 
 
Peter Makholm
Guest
Posts: n/a
 
      09-09-2008
Jerry Krinock <(E-Mail Removed)> 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
 
Reply With Quote
 
 
 
 
Joost Diepenmaat
Guest
Posts: n/a
 
      09-09-2008
Jerry Krinock <(E-Mail Removed)> 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/
 
Reply With Quote
 
xhoster@gmail.com
Guest
Posts: n/a
 
      09-09-2008
Peter Makholm <(E-Mail Removed)> wrote:
> Jerry Krinock <(E-Mail Removed)> 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.
 
Reply With Quote
 
Eric Pozharski
Guest
Posts: n/a
 
      09-11-2008
http://www.velocityreviews.com/forums/(E-Mail Removed) 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
 
Reply With Quote
 
xhoster@gmail.com
Guest
Posts: n/a
 
      09-12-2008
Eric Pozharski <(E-Mail Removed)> wrote:
> (E-Mail Removed) 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.
 
Reply With Quote
 
xhoster@gmail.com
Guest
Posts: n/a
 
      09-12-2008
(E-Mail Removed) wrote:
> Eric Pozharski <(E-Mail Removed)> 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.
 
Reply With Quote
 
Eric Pozharski
Guest
Posts: n/a
 
      09-12-2008
(E-Mail Removed) 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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
hash of hash of hash of hash in c++ rp C++ 1 11-10-2011 04:45 PM
Iterating over a hash of hash of hashes Steven Hirsch Ruby 0 08-19-2008 12:34 AM
Iterating list in pairs FireAphis Ruby 12 08-09-2007 04:33 AM
Iterating over an area in pairs. Thaddeus L Olczyk Ruby 7 05-09-2006 09:44 AM
hash in hash, iterating the members Depili Ruby 5 01-13-2006 03:06 AM



Advertisments