rsiedl has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

Can anyone tell me if it is possible to delete a hash key/value while running a foreach on that hash?

Here is an example to demo what I'm trying to do:
#!/usr/bin/perl use strict; my %test = (); $test{11} = "reagen"; $test{26} = "daniel"; $test{13} = "joe"; foreach my $id (sort keys %test) { print "$id :: $test{$id}\n"; # Delete joe from the hash delete $test{13} if ($test{13}); } # end-foreach exit;
This returns:
11 :: reagen
13 ::
26 :: daniel
But I would like to remove the id as well...?

Cheers,
Reagen

Replies are listed 'Best First'.
Re: delete hash key while hash in use
by ikegami (Patriarch) on Jul 27, 2006 at 02:18 UTC

    It is getting deleted. If you print the hash after the loop (well, anytime after the delete), you'll notice it only has two keys.

    foreach my $id (sort keys %test) { delete $test{13}; } print(scalar keys %test, "\n"); # 2

    Your code is equivalent to

    @anon_list = sort keys %test; foreach my $id (@anon_list) { print "$id :: $test{$id}\n"; delete $test{13}; }

    The problem is that you are deleting the key from %test, but not from the list over which foreach is iterating (@anon_list). That list is built when the loop is entered, before delete is called.

    A solution is to check if the key still exists when you get around to visiting it.

    foreach my $id (sort keys %test) { next if not exist $test{$id}; print "$id :: $test{$id}\n"; delete $test{13}; }
Re: delete hash key while hash in use
by GrandFather (Saint) on Jul 27, 2006 at 02:52 UTC

    Perhaps you need to elaborate on your problem? The key 13 and its value are being removed. However, why need yo do it in the for loop? Wouldn't it be simpler to remove it up front? Consider:

    use warnings; use strict; my %test = (11 => "reagen", 26 => "daniel", 13 => "joe"); delete $test{13}; print "$_ :: $test{$_}\n" for sort keys %test;

    which prints:

    11 :: reagen 26 :: daniel

    If you need to iterate over the hash entries, manipulate them in some fashion that may depend on other values or keys, then do something with the result you really need two loops. Consider:

    use warnings; use strict; my %test = (11 => "reagen", 26 => "daniel", 13 => "joe"); for (sort keys %test) { delete $test{$_ - 13} if exists $test{$_ - 13}; } print "$_ :: $test{$_}\n" for sort keys %test;

    Prints:

    11 :: reagen 26 :: daniel

    DWIM is Perl's answer to Gödel
Re: delete hash key while hash in use
by planetscape (Chancellor) on Jul 27, 2006 at 06:39 UTC
Re: delete hash key while hash in use
by rhesa (Vicar) on Jul 27, 2006 at 02:14 UTC
    update: Have you considered that you are printing before deleting? -- As usual, ikegami is my perl -c :)

    For more details, see delete. -- this is still useful, of course.