There's more than one way to do things PerlMonks

### Test for the last element in a foreach

 on Aug 02, 2007 at 20:01 UTC Need Help??
tdevil76 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks, What is the cleanest(i.e. short and sweet) way to know if you are working on the last element of the array in a foreach? Thanks!

UPDATE: Sorry - I should be more specific - It isn't an array per se, but a function that is returning an array, i.e.:

foreach \$subcat (\$category->children) {
# is this the last element?
}

Replies are listed 'Best First'.
Re: Test for the last element in a foreach (==\)
by tye (Sage) on Aug 02, 2007 at 20:16 UTC

Since you said "array", you can use \\$_ == \\$array[-1]:

```my @array= ( 1..5 );
for( @array ) {
if(  \\$_ == \\$array[-1]  ) {
print "Last element.\n";
}
print \$_, \$/;
}
__END__
1
2
3
4
Last element.
5

Update: ikegami asked about Data::Alias being able to confuse this test. Yes, that can be done, and one can even do it w/o such a module but it requires some unusual contortions and so probably isn't something to worry too much about:

```my \$five= 5;
*array= sub { \@_ }->( 1, 2, \$five, 4, \$five );
for( @array ) {
if(  \\$_ == \\$array[-1]  ) {
print "Last element.\n";
}
print \$_, \$/;
}
__END__
1
2
Last element.
5
4
Last element.
5

- tye

Re: Test for the last element in a foreach
by ikegami (Pope) on Aug 02, 2007 at 20:14 UTC

In the CB, I presented:

```for my \$i (0..\$#array) {
for (\$array[\$i]) {
...
if (\$i == \$#array) { ... }
...
}
}

Using this method, no change will be required to the body of your loop. \$_ is still aliased to the array element as it normally is in a foreach loop. Changes to it will be reflected in the array.

Re: Test for the last element in a foreach
by almut (Canon) on Aug 02, 2007 at 20:21 UTC

Yet another variant:

```my @elems = qw(a b c d e);

my \$n = \$#elems;
for my \$elem (@elems) {
print "last elem = \$elem\n" if !\$n--;
}

Update: as to your updated question: if you want to avoid creating a named array at any price, you could do something like this (but I'm not sure if I should seriously recommend that...)

```my \$n;
for my \$elem (map {\$n++; \$_} qw(a b c d e)) {
print "last elem = \$elem\n" if !--\$n;
}
Re: Test for the last element in a foreach (list)
by tye (Sage) on Aug 02, 2007 at 20:47 UTC

With your update, you could just assign the returned list to a named array. Or, for fun, do something crazy like:

```sub children { return ( 1..5 ); }
my( \$end, \$subcat );
foreach my \$next (  children(), \$end  ) {
if(  ! \$end  ) {
\$end= 1;
\$subcat= \$next;
next;
}
if(  \\$next == \\$end  ) {
print "Last element.\n";
}

print \$subcat, \$/;

\$subcat= \$next;
}
__END__
1
2
3
4
Last element.
5

- tye

Re: Test for the last element in a foreach
by CountZero (Bishop) on Aug 02, 2007 at 20:30 UTC
I was thinking of:
```my @array = (1 .. 10);
my \$counter;
foreach my \$element (@array) {
print "Last element follows now!\n"    if ++\$counter == scalar(@ar
+ray);
print "\$element\n";
}

Output:

```1
2
3
4
5
6
7
8
9
Last element follows now!
10

You can leave out the scalar function but then you have to take care that the test does not get evaluated in list context.

CountZero

A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Test for the last element in a foreach
by wind (Priest) on Aug 03, 2007 at 00:39 UTC
If you care about the position of elements in an array, you should simply iterate them by index instead of by element.
```my @children = \$category->children;
for my \$i (0..\$#children) {
my \$subcat = \$children[\$i];
my \$is_last = \$i == \$#children;

# More code here.
}
There is nothing particularly elegant or fancy about this solution. In fact, it's down right boring. However, it's very clear what purpose each variable serves. And so is very maintainable.

There are other abstractions that you could use that are more both elegant or obfuscated. One good way would be to use an Iterator class. However, this needlessly adds more dependencies to something that is honestly very basic, so I at least wouldn't bother.

- Miller
Re: Test for the last element in a foreach
by mvc (Scribe) on Aug 03, 2007 at 13:29 UTC
No need for a test on each iteration:
```my @children   = \$category->children;
my \$last_child = pop @children;

foreach \$child (@children) {
handle_not_last_child(\$child);
}

handle_last_child(\$last_child);
Nice mvc++, I like your solution.
Re: Test for the last element in a foreach
by NetWallah (Canon) on Aug 03, 2007 at 04:23 UTC
This seems the simplest/cleanest to me:
```my \$LastSubCat;

foreach my \$subcat (\$category->children) {
\$LastSubCat = \$subcat;
# Code to use \$subcat
}

# \$LastSubCat now contains the value of the last element

"An undefined problem has an infinite number of solutions." - Robert A. Humphrey         "If you're not part of the solution, you're part of the precipitate." - Henry J. Tillman

Create A New User
Node Status?
node history
Node Type: perlquestion [id://630377]
Approved by almut
Front-paged by mr_mischief
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (8)
As of 2018-04-24 19:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My travels bear the most uncanny semblance to ...

Results (88 votes). Check out past polls.

Notices?