Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re: Turning foreach into map?

by jZed (Prior)
on Apr 04, 2005 at 20:23 UTC ( [id://444785]=note: print w/replies, xml ) Need Help??


in reply to Turning foreach into map?

Simply this will do: return map {"$url/$_\n"} @list;

update note the curly braces instead of parens

Foreach can be faster than map, so depending on how many times that sub gets called, you may not want to make the change.

Replies are listed 'Best First'.
Re^2: Turning foreach into map?
by jhourcle (Prior) on Apr 05, 2005 at 01:39 UTC

    Foreach is faster than map if you're modifying in place. If you're using foreach to push into an array, like what's happening here, then map is going to be faster. (which is why there's the recommendation not to use map if you're not doing anything with the list generated -- you might as well have just done foreach).

    Update: benchmarks to show the speed differences between map, map reassigning to the original list, map in void context, for, and foreach. (if 'recent' is before 5.8.6, I don't think the optimizations worked)

    purple:/tmp oneiros$ perl -version | head -2 This is perl, v5.8.6 built for darwin-thread-multi-2level purple:/tmp oneiros$ perl timer.pl 100: Rate map new_map void_map for foreach map 1089/s -- -16% -37% -61% -61% new_map 1295/s 19% -- -25% -54% -54% void_map 1718/s 58% 33% -- -38% -39% for 2793/s 156% 116% 63% -- -1% foreach 2825/s 159% 118% 64% 1% -- 500: Rate map new_map void_map foreach for map 213/s -- -14% -35% -60% -60% new_map 249/s 17% -- -24% -53% -54% void_map 328/s 54% 32% -- -38% -39% foreach 526/s 147% 112% 61% -- -2% for 538/s 153% 116% 64% 2% -- 2500: Rate map new_map void_map for foreach map 38.5/s -- -15% -38% -61% -61% new_map 45.4/s 18% -- -27% -54% -55% void_map 61.9/s 61% 37% -- -38% -38% for 99.5/s 158% 119% 61% -- -0% foreach 100.0/s 160% 120% 61% 0% --
      Foreach is faster than map if you're modifying in place. If you're using foreach to push into an array, like what's happening here, then map is going to be faster. (which is why there's the recommendation not to use map if you're not doing anything with the list generated -- you might as well have just done foreach).
      This is no longer the case for recent versions of perl. Now map has been optimized in void context, so if you don't do anything with the return values, it doesn't bother generating them.

      In theory, the only difference between map and for/foreach now is a matter of taste/style. (I say "in theory", because I haven't benchmarked it, and sometimes the perl porters *think* they've done, isn't quite what they've done.)

        In theory, the only difference between map and for/foreach now is a matter of taste/style.
        And the ability to have a named variable as your index.

        Caution: Contents may have been coded under pressure.
Re^2: Turning foreach into map?
by dragonchild (Archbishop) on Apr 04, 2005 at 20:30 UTC
    Foreach can be faster than map, so depending on how many times that sub gets called, you may not want to make the change.

    Proof? Caveats? Situations? You can't just throw that statement out there and expect it to stand on its merits ...

      use strict; use warnings; use Benchmark (); sub t_for_r { my ($url, $list) = @_; my @return; push(@return, "$url/$_\n") foreach @$list; return @return; } sub t_map_r { my ($url, $list) = @_; my @return = map { "$url/$_\n" } @$list; return @return; } sub t_map2_r { my ($url, $list) = @_; return map { "$url/$_\n" } @$list; } sub t_for_a { my $url = shift; my @return; push(@return, "$url/$_\n") foreach @_; return @return; } sub t_map_a { my $url = shift; my @return = map { "$url/$_\n" } @_; return @return; } sub t_map2_a { my $url = shift; return map { "$url/$_\n" } @_; } { my $url = 'http://www.domain.com/'; my @list = qw( file0 file1 file2 file3 file4 file5 file6 file7 file8 file9 ); Benchmark::cmpthese(-3, { t_for_r => sub { $a = join('', t_for_r ($url, \@list)); }, t_map_r => sub { $a = join('', t_map_r ($url, \@list)); }, t_map2_r => sub { $a = join('', t_map2_r($url, \@list)); }, t_for_a => sub { $a = join('', t_for_a ($url, @list)); }, t_map_a => sub { $a = join('', t_map_a ($url, @list)); }, t_map2_a => sub { $a = join('', t_map2_a($url, @list)); }, }); } __END__ Rate t_for_r t_map_r t_for_a t_map_a t_map2_r t_map2_a t_for_r 20641/s -- -3% -5% -5% -33% -36% t_map_r 21196/s 3% -- -2% -2% -31% -34% t_for_a 21651/s 5% 2% -- -0% -29% -33% t_map_a 21684/s 5% 2% 0% -- -29% -32% t_map2_r 30598/s 48% 44% 41% 41% -- -5% t_map2_a 32087/s 55% 51% 48% 48% 5% --

      At least for small lists, t_for and t_map are the same, and t_map2 is much faster.

      Passing by ref vs passing the array doesn't matter if you use @_ directly.

        The other common condition that makes map slower than the equivalent foreach/push is having more output elements than input elements. I'll leave the benchmarking to someone else.

        ID be interested to see the EXPR form of the map statements timed too, iirc they are quicker than the block forms.

        ---
        demerphq

        Please be aware that the benchmark doesn't show that in this case map is faster than foreach. The fact that t_map2_r and t_map2_a are faster is that the subs don't collect the results into an array, and then return the flattened array, but return the results of the map directly. The overhead of the extra duplication of the result data is more significant than the difference between for and map.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://444785]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (2)
As of 2024-04-24 22:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found