Is using nested map in perl a good practice?

4.7k views Asked by At
my @c= map {
        my $v=$_;
        map {$_ * $v } @m
} @a;

Is using map like this, a good practice? Why not? If not, what are other ways?

4

There are 4 answers

0
Moritz Bunkus On BEST ANSWER

I cannot answer whether or not it is good practice. In general there are a lot of situations in which I use nested maps a lot. It's short, it's concise and to the point.

However, such nested maps are always in danger of growing just slightly too big and unwieldy in which case they become harder to read than they have to (which list does $_ refer to in which case!?). So use them, yes, but use it with caution -- just like all other similar things that make Perl so terse and expressive.

4
David W. On

I've always had mixed feelings at the map command. There are lots of pitfalls using map, and It is one of those things that makes Python people gloat at how unreadable Perl is. Besides, the map isn't really all that much more efficient than using a regular loop.

There's a gotcha when map modifies the value of $_ because it's really just an alias for the value in the original array. Modify $_, and you modify your original array. Maybe that's what you want, but the map command can obscure that. There's a discussion in Perl Monks about map.

Even if your use of map within map actually works (map does localize $_ for you, so the $_ in one map isn't the same as $_ in the other map), there's the issues of readability and maintainability.

Use map only when the usage is clear and easy to understand the context. Save the Clever Perl Tricks for email sigs. I wouldn't use map-within-map.

2
darch On

Nested map has the same problem and the same solution as any other nested structure, except amplified slightly by the need to reassign $_. The fact that a nested map doesn't flow as well is a code smell: your code is trying to tell you that you should structure it slightly differently.

And the appropriate change is to make the inner operation into a function call such that the reader doesn't have to track both scopes at the same time. In that case, you get:

sub scale {
    my ($factor, @numbers) = @_;

    return map { $factor * $_ } @numbers;
}

my @c = map { scale($_, @m) } @a;
1
ikegami On

I'm not sure what you mean. It'll work perfectly fine, or are you asking about readability? It can be harder to read a long map compared to the equivalent foreach loop.

my @c;
for my $v (@a) {
   push @c, map { $_ * $v } @m;
}