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 | [reply] [d/l] [select] |
|
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
| [reply] [d/l] |
|
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. | [reply] [d/l] [select] |
|
|
|
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...
}
| [reply] [d/l] [select] |
|
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. | [reply] [d/l] [select] |
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. | [reply] |
|
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.
| [reply] |
|
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. | [reply] [d/l] |
|
|
|
|
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. | [reply] [d/l] [select] |
|
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}
| [reply] [d/l] [select] |
|
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 );
| [reply] [d/l] [select] |
|
|
|