in reply to When should I use map, for?

So, I might be mistaken here, but:

sub { my @e = map { $_ if (s/0/./g || 1) } @elem }

modifies global @elem in place. The s///g acts on $_, which is an alias to the list item. After the first iteration of mapc, you've altered the sample data. Not sure that matters, as this is a /g it has to inspect all the characters regardless.

As has been mentioned already, the map versions both have two needless logical branches, which taints the results.

A better comparison might be something that doesn't act in-place. Like an addition:

my @b = map { $_ + 2 } @elem; # vs my @b; for ( @elem ) { push @b, $_ + 2; } # -> results: # Rate map for # map 60.3/s -- -23% # for 78.2/s 30% --

Replies are listed 'Best First'.
Re^2: When should I use map, for?
by radiantmatrix (Parson) on May 19, 2005 at 21:06 UTC
    That particular map does not modify @elem in-place. Rather, it copies one element at a time, leading to the same result. The needless logical branch isn't, because map would otherwise return a list of the results of the s///.

    I'm aware that the extra logical branch adds a small amount of complexity; However, the || short-circuts, so if a substitute is made, the '1' isn't evalated. Also, the '1' doesn't take a lot of time to evaluate. It's also needed to accomplish the substitution in that way. Even in your results the for is notably faster -- so your point seems moot anyhow.

    When is map more appropriate (faster) than for, and vice-versa?


    The Eightfold Path: 'use warnings;', 'use strict;', 'use diagnostics;', perltidy, CGI or CGI::Simple, try the CPAN first, big modules and small scripts, test first.

      Have you tried it? It copies -and- modifies -both-.

      my @elem = ( 1..20 ); my @e = map { $_ if (s/0/./g || 1) } @elem; print join( " ", @elem ), "\n"; __END__ 1 2 3 4 5 6 7 8 9 1. 11 12 13 14 15 16 17 18 19 2.

      I understand -why- you put the logical path there. Just saying s/0/./g; $_; makes more sense than the if and or.

      But you are quite right. It is moot. map is still slower, though arguably clearer in the $_ + 2 case. I don't know that map {} is ever an optimization.

      I would use grep to filter records, or map to preprocess going into a sort. I find that makes sense to me coding-wise. I doubt that it is better speed-wise.

      addendum:

      Okay, here is a case where I think map is cleaner and (slightly) faster:

      my @elem = map { int rand 1000 } 1..10000; sub map_s { my @mod_sorted = sort { $a <=> $b } map { $_ % 2**6 } @elem; } sub for_s { my @a; for ( @elem ) { push @a, $_ % 2**6; } my @mod_sorted = sort { $a <=> $b } @a; } __END__ Rate for map for 15.8/s -- -4% map 16.5/s 4% --

        In your for_s() test, the creation of the extra array may taint the results. What happens to that test when you eliminate the sort, and just create an array of the mod values?