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

Why do you have to use "while" in the following loop? I tried using for/foreach, but then the output is wrong.
my %hash = ("one" => 1, "two" => 2, ); while ((my $key, my $value) = each %hash) { print $key, "\n"; }
Prints:
one
two
foreach ((my $key, my $value) = each %hash) { print $key, "\n"; }
Prints:
one
one

Replies are listed 'Best First'.
Re: Learning to use "each"
by toolic (Bishop) on Apr 28, 2011 at 19:08 UTC
    I don't think Foreach Loops support multiple iterator variables like that. Take a look at this B::Deparse output (tip #6 from Basic debugging checklist):
    $ perl -MO=Deparse 901847.pl use warnings; use strict 'refs'; { my(%hash) = ('one', 1, 'two', 2); foreach $_ (my($key, $value) = each %hash) { print $key, "\n"; } }
    It shows that the loop is really using $_ for the iterator.

    Update: Now I have changed the OP code a little, just to print more info:

    use warnings; use strict; my %hash = ("one" => 1, "two" => 2, ); foreach ((my $key, my $value) = each %hash) { print "\$key=$key \$value=$value \$_=$_\n"; } __END__ $key=one $value=1 $_=one $key=one $value=1 $_=1

    It seems like each is evaluated once in list context. It happens to choose the 'one' key and stores that in $key and stores the value '1' in $value. It never evaluates each again. Then each time through the loop, each item of the list ('one', '1') is assigned to $_.

      Explaination:
      That prints 'one' twice. It's iterating over the return value of each, so over a single $key, $value pair, printing the value of $key twice.
        I don't think that's what the OP wants.
        I think you misunderstood my post. I simply ran the OP's foreach code through the deparser to show how perl interprets the code. I simply showed the output of the OP's deparsed code. I did not suggest any new code.
Re: Learning to use "each"
by JavaFan (Canon) on Apr 28, 2011 at 19:00 UTC
    Because each returns a 2 element list. for iterates over one element at a time. How did you imagine to use for in combination with each?
Re: Learning to use "each"
by Not_a_Number (Prior) on Apr 28, 2011 at 19:36 UTC

    Hi.

    The reasons why your code snippet doesn't work have been explained (I hope to your satisfaction?).

    However, if you're interested in visualising only the keys of your hash, each is not really your friend. Do this instead:

    for my $key ( keys %hash ) { print $key, "\n"; }

    Or, even more succinctly:

    print "$_\n" for keys %hash;
Re: Learning to use "each"
by mr_mischief (Monsignor) on Apr 28, 2011 at 21:00 UTC

    Just to make this either clearer or murkier (I'm not sure which, but more information is good, right? (well, sometimes))...

    If you really, really want a for loop then you could do this with a C-like for loop which is not the same as the foreach loop or the foreach loop abbreviated as for. Confused yet? Either way, good! (Read it until you aren't. The confusion is the earliest stage of learning.) Let's carry on.

    Take a look at this:

    my %hash = ("one" => 1, "two" => 2, ); for ( my ( $key, $value ) = each %hash ; defined $key ; ( $key, $value + ) = each %hash ) { print $key . ': ' . $value . "\n"; }
    That's ugly and messy, isn't it? All it's doing is setting a precondition for a couple of variables, testing the whether one of those is defined to determine whether to loop again, and updating the same variables at the end of every iteration. You could take out the defined if you want to test truthiness rather than definedness. It seems there should be a shorthand for a loop that does that all with the same variable set.

    Now, look at this:

    my %hash = ("one" => 1, "two" => 2, ); while ((my $key, my $value) = each %hash) { print $key, "\n"; }
    Now, what three things is that loop construct doing? Read perlsyn if it's not obvious (at least the part about loop constructs).

    Now, if you don't understand the differences among for, foreach/for, while, and until (not to mention do-while, do-until, and all the control modifiers like next, last, and continue) all at once, don't worry. Read perlsyn again, and play with loops.

    An aside...
Re: Learning to use "each"
by locked_user sundialsvc4 (Abbot) on Apr 29, 2011 at 02:21 UTC

    each is “a really-nifty language feature” that is not entirely without its own peculiar set of ... ahhhh ... “issues.”   This function, convenient though it certainly is, does rely upon a bit of “hidden” contextual information that can, shall we say, “surprise you” if you happen to be using it in nested-loops or other “tricky” situations.   For this reason, some folks love to use it, while other folks studiously find other ways to do the same thing.   (Fortunately, “this is Perl.”   TMTOWTDI™ ...)