tags:

views:

146

answers:

6

In Perl, is it possible to arbitrarily end a map execution, e.g. something equivalent to last in a loop?

It would be a bit like this:

map {
    if (test == true) { last; } dosomething
} @myarray
+15  A: 

Nope. You can't last, next, etc. out of a map, grep or sort blocks because they are not loops.

Having said that, the code snippet in the question is poor practice because map should never be called in void context. They are supposed to be used to transform one list into another.

Here's a better way to write it if you really must inline it (modified after ysth's comment):

 $_ == 10 && last, print for 1..15;  # prints '123456789'
Zaid
thank you for your answer. About the "poor parctice" thing, well ... the "dosomething" piece of code is intended to .... do something
benzebuth
@benzebuth : I wasn't talking about the `do_something`. You should be really be using `map` to return a list.
Zaid
thanks. Now i get it. Very usefull indeed. +1
benzebuth
ysth
@ysth : Thanks for the heads up, I always forget about the comma operator.
Zaid
Sometimes it's best to forget to use the comma operator this way.
William Pursell
+3  A: 

No. Use an ordinal foreach loop and the last statement.

Since 5.8.1, map is context aware - in void context, no lists are constructed. Anyway, map is generally used to get a list from another list, evaluating expr for each element of the original list.

eugene y
+2  A: 

You can use a long jump (eval/die pair) to bail out of any nested construct that doesn't directly support it:

eval { map{ die if test; dosomething } @myarray };

But as Zaid said, using a for/foreach loop in this case is better because you are not using the return value of map.

Eric Strom
map doesn't construct a list in void context: http://perldoc.perl.org/perlfaq6.html#What%27s-wrong-with-using-grep-in-a-void-context?
eugene y
@eugene => that's true, but it is a bit misleading to use `map` without the return value. if you want the inverted position of action and values, its better to use `dosomething for ...'
Eric Strom
@Eric Strom: the exception being when you for some reason want to provide dosomething list context (but don't actually want the returned list) - a rare case. for provides void context to dosomething (and grep would provide scalar context)
ysth
+2  A: 

You want a for loop:

foreach ( @myarray ) { 
    last if test;
    ...
}

It does the same thing. map is for transforming one list into other lists.

Axeman
+3  A: 

You could use a do-block with a for statement modifier:

do {
   last if test;
   dosomething;
} for (@myarray);

Though using a foreach block would probably be clearer, and future maintainers of your code will thank you.

foreach (@myarray) {
   last if test;
   dosomething;
}
MkV
+1  A: 

There are map-like constructs that do exactly what you want to do. Take a look at List::Util and List::MoreUtils (conveniently also packaged together as List::AllUtils):

use List::MoreUtils 'first';

# get first element with a {foo} key
my $match = map { $_->{foo} eq 'some string' } @elements;

If you don't want to extract an element(s) from the list, then use foreach, as per the previous answers.

Ether