Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Map Vs Foreach

by perlCrazy (Monk)
on Nov 26, 2009 at 05:40 UTC ( [id://809482]=perlquestion: print w/replies, xml ) Need Help??

perlCrazy has asked for the wisdom of the Perl Monks concerning the following question:

Question: is 'map' really faster than 'foreach' ? under what circumastances we should use map and why not foreach ?
Thanks in advnace.

Replies are listed 'Best First'.
Re: Map Vs Foreach
by Ratazong (Monsignor) on Nov 26, 2009 at 06:44 UTC
    You might also check map versus for. There for and map are compared, and there is even some benchmark-measurement-code provided ... which you can adapt to measure the foreach - performance.


    HTH, Rata
      Thanks for reply. i did some benchmarking and found that map is slower than foreach.
      Also I was under impression that map is actually faster than foreach, but my result is different !
      #!/opt/gsperl-5.8.6_1/bin/perl use strict; use Benchmark; my ($start,$end,$diff); my @data = (1..20000000); # start timer $start = new Benchmark; my %dataseen; my @arr; foreach my $x (@data) { push @arr, ($x+2); } # end timer $end = new Benchmark; # calculate difference my $diff = timediff($end, $start); # report print "Time taken by foreach loop was ", timestr($diff, 'all'), " seco +nds\n"; my $start1 = new Benchmark; my @arr1; @arr1 = map { push @arr1, ($_+ 2) } @data; # end timer my $end1 = new Benchmark; # calculate difference my $diff1 = timediff($end1, $start1); # report print "Time taken by map block was ", timestr($diff1, 'all'), " second +s\n";
      and output of code :
      Time taken by foreach loop was 9 wallclock secs ( 8.22 usr 0.32 sys + 0.00 cusr 0.00 csys = 8.54 CPU) seconds
      Time taken by map block was 15 wallclock secs (14.88 usr 0.72 sys + 0.00 cusr 0.00 csys = 15.60 CPU) seconds
        For what its worth:
        I was unhappy about your benchmark, since the two types of code did not appear to be the same:
        @arr1 = map { push @arr1, ($_+ 2) } @data;
        in particular seemed suspect to me. Also the order of memory allocation can affect benchmarks. When I ran the supplied code the foreach loop worked fine (5 seconds on my machine) but the map gave Out of memory!.

        So I rewrote each part to be a subroutine, and tided the map so it looked like this:
        sub mapsub { my @arr; @arr = map { ($_ + 2) } @data; }
        I can't say if that was faster, because it still gives Out of memory! Must be something to do with a temporary list (5.10.1 on Windows). Reducing the size of @data by a factor of 10 gives map taking around twice as long, and each taking under a second.
        Well....
        my @arr1; @arr1 = map { push @arr1, ($_+ 2) } @data;
        is not the way to use map to generate a new list of @data with values of +2. here is the right way...
        my @dataPlus2 = map { my $bullshit = 'XYZ'; #see below $_ + 2 }@data;
        map{} returns the value of the last statement. I put this $bullshit statement in there to "throw you off"...it means absolutely nothing!

        Use the power of the language.

        my @dataPlus2 = map { $_ + 2 }@data;
        my @roots = map { sqrt($_) }@data;

        map{} is best used for a line or two translations.

        I wouldn't normally do it this way, this is just to show you that it is possible:

        foreach my $root (map { sqrt($_) }@data) { #do something with this square root... }
Re: Map Vs Foreach
by kyle (Abbot) on Nov 26, 2009 at 13:48 UTC

    Use whichever one most clearly conveys the meaning and intention of the loop in question. I use map for transforming one list to another list. I use grep for filtering items out of a list to produce a new list. I use for to iterate over a list for basically any other reason.

    Do not concern yourself with the performance of a looping construct (or anything else) until you've determined that performance is a problem and you've profiled the code and found a particular loop to be the source of the performance problem. Before that, you're making your code more obscure in order to solve a problem that might not even be there.

    It's a rare loop whose execution time is influenced by the method of iteration. Look at the examples in this thread. To see differences between map and for, monks are writing loops that do naught more than simple addition. Consider this loop instead:

    for my $ip ( @accessors ) { system( 'host', $ip ) == 0 or die "system(host) failed: $?"; }

    Would that be faster or slower with map or grep? I doubt it. The call to system is likely taking nearly all of the time, and most of that time is spent waiting on the name server being queried by the 'host' command. Converting this to some other looping construct would have a much greater effect on comprehensibility than on its execution speed and often times clear code is more valuable than fast code anyway.

Re: Map Vs Foreach
by Marshall (Canon) on Nov 26, 2009 at 06:30 UTC
    map{} will not be faster than foreach!!! map is a slow but very powerful critter. map{} takes an input array and makes a new output array. foreach my $x (@input){} iterates over an existing array. @output = map{...}@input, makes a new array from the input - it transforms one array into a new array. Don't use map{} if you don't use the output of map{}, ie there should always be some use of the map array output.
      map is a slow

      Why do you say that?

      map{} takes an input array and makes a new output array

      map transforms lists, not only arrays. Likewise, for iterates over lists.

      As well, map doesn't have to produce any output. A void context map is poor style in my book, but there's no performance penalty in modern Perls.

        map{} is a wrong idea if the output isn't being used. That is why it can be "slow". But I am hearing that there is no performance penalty for a "void map{}"... meaning that Perl won't create and allocate memory for the output of map{} if is not being used? I didn't know about that. When did this performance enhancement happen?

        I think we both agree that a "void map{}" is bad style. I looked at the post from Ratazong and saw the following code being bench marked:

        my @sqrt_results = map { sqrt ($_ ) } @input;
        This is a perfect thing for map{}: translate one thing to another. map{} can also make 1 to many and many to one translations. In general, I use map{} when the transformation can be expressed as a "one liner+" and foreach() when the code is longer. As a matter of style, this allows me to put foreach(@input) at the top instead of at the end of the program text, compare with: @output = map{lots of lines}@input.
Re: Map Vs Foreach
by ikegami (Patriarch) on Nov 26, 2009 at 16:18 UTC
    Who case about speed, they don't do the same thing. map transforms a list and for visits each element of a list.
      They both "visit" each element of a list (I would say, they both execute a block of code for each element of a list). The main difference is that for is a statement, map is an expression. As such, map has (in non-void context) a return value.

      Only if you assign the return value of map to an array, and you have the same array as input list to the map, one could say that map 'transforms' a list. But then it's the combination of map and the assign statement.

      The only way I can think of map on its own "transforming" a list is constructs like:

      map {$_ = ucfirst} @array;
      But for knows that trick as well:
      for (@array) {$_ = ucfirst}

        The both "visit" each element of a list

        I was talking about their purpose.

        The only way I can think of map on its own "transforming" a list is constructs like:

        The whole purpose of map is to transform a list.

        my @b = map uc, @a; # 1 to 1 my @b = map { $_ => uc($_) } @a; # 1 to N, const ratio my @b = map { /^#/ ? () : $_ } @a; # 1 to N

        But then it's the combination of map and the assign statement

        No way. You don't have to assign the list to anything. You could pass it to join, for example.

        print join '|', map uc, qw( a b c );

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (8)
As of 2024-04-23 11:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found