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

Hi Monks, I'm trying to determine *within* the loop whether this iteration is the last. Is there a better perlish way to do this besides using a counter?
foreach my $element (keys %$hash) { if (lastElement) { #do this } else { #do that } }
I guess I'm wondering if Perl sets some global variable to true once it hits the last element... thanks, Michael

Replies are listed 'Best First'.
Re: Last Element of Hash (no magic)
by tye (Sage) on Sep 25, 2003 at 20:15 UTC

    my $left= keys %$hash; foreach my $element ( keys %$hash ) { if( 0 < --$left ) { # not last } else { # last } }

                    - tye
Re: Last Element of Hash
by liz (Monsignor) on Sep 25, 2003 at 20:42 UTC
    This will not load all the keys in memory, which may make sense for large hashes:
    my $last = each %hash; while (defined $last) { my $next = each %hash; if (defined $next) { # $last is now set, but is _not_ the last, do what you want with it } else { # $last is now _the_ last, do what you want with it. } $last = $next; }

    Liz

    Update:
    Removed next;, leftover from a previous version, not needed with this approach.

Re: Last Element of Hash
by dragonchild (Archbishop) on Sep 25, 2003 at 20:24 UTC
    my @keys = keys %hash; foreach my $i (0 .. $#keys) { my $element = $keys[$i]; if ($i == $#keys) { #do this } else { #do that } }

    *shrugs* There's a bazillion ways to do it.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Last Element of Hash
by seaver (Pilgrim) on Sep 25, 2003 at 22:51 UTC
    waswas-fng hit the nail on the head I believe, seeing hashes iterate in a seemingly random order, I can only assume that you actually SORT your keys into some kind of order, whence you can find the last key alphanumerically, am I right?

    In which case, liz's answer is a good one, because depending on the order of the sort, you can always find not only the last key, but the last one alphanumerically, or the first one, if your sort is ascending instead.

    Liz's answer is even the more useful if you're looking for the 'last' out of several hashes. In the real-life example Im giving below, I created two hashes labelled 'atoms' and 'protons'. Their keys are the actual line numbers from a flat file, where each atom/proton had it's own line.

    Hence by iterating the line numbers themselves(extracted here from a 'residue'), I can get the true last atom/line of a residue.

    foreach my $ref (sort keys %{$self->{'residues'}{'1'}}){ $last=$self->{'atoms'}{$ref} if defined $self->{'atoms'}{$ref}; $last=$self->{'protons'}{$ref} if defined $self->{'protons'}{$ref} +; }
    Cheers
    Sam
Re: Last Element of Hash
by LazerRed (Pilgrim) on Sep 25, 2003 at 20:41 UTC
    I was thinking something like:

    my @elements = ( keys %hash ); foreach (@elements){ if ( $_ eq $elements[-1] ){ #Do something to last element }else{ #Do something to an item in element } }

    To me, it's easier to see it that way... I'm still rather "young" on Perl :-)
    caveat: above will give warnings if @elements is full of numbers...

    LR

    Update: Changed @elements[-1] to $elements[-1]

    Whip me, Beat me, Make me use Y-ModemG.
      caveat: above will give warnings if @elements is full of numbers...
      No it won't. You can always use a number as a string without any warning. The reverse isn't always true.

      And besides, here, the elements are originally hash keys. Hash keys are always strings.

        Thanks for the clarification... I still get confused sometimes over the little details, but I'm slowly getting the hang of it :-)

        LR

        Whip me, Beat me, Make me use Y-ModemG.
Re: Last Element of Hash
by waswas-fng (Curate) on Sep 25, 2003 at 21:01 UTC
    This is only really a useful thing to do if you are trying to show that no match was found or something else did not hapen in the loop. It may be more readable to just do that same test after the loop has finished.

    -Waswas
Re: Last Element of Hash
by bart (Canon) on Sep 26, 2003 at 10:45 UTC
    Here's a rather silly Other Way To Do It. Look, ma, no temporary array:
    my $last = (keys %hash)[-1]; foreach my $element (keys %$hash) { if ($element eq $last) { #do this } else { #do that } }

    I just added this as just something to play with. I don't think I'd ever use it in production code myself.