Perldoc for List::Util suggests that some uses of map
may be replaced by reduce
in order to avoid creating unnecessary intermadiate list:
For example, to find the total length of the all the strings in a list, we could use
$total = sum map { length } @strings;
However, this produces a list of temporary integer values as long as the original list of strings, only to reduce it down to a single value again. We can compute the same result more efficiently by using reduce with a code block that accumulates lengths by writing this instead as:
$total = reduce { $a + length $b } 0, @strings;
That makes sense. However, reduce
in order to work in this example needs "identity value", that would be prepended to input list:
$total = reduce { $a + length $b } 0, @strings;
# ^^^^^^^^^^^
That makes me think, doesn't 0, @strings
create a new list, thus offset any gains from not creaing list in map
?
How does list interpolation ($scalar, @list)
work in Perl? Does it involve copying elements from source list or is it done in some smarter way? My simple benchmark suggests copying taking place:
use strict;
use warnings;
use Benchmark qw/cmpthese/;
my @a1 = 1..10;
my @a2 = 1..100;
my @a3 = 1..1000;
my @a4 = 1..10000;
my @a5 = 1..100000;
my @a6 = 1..1000000;
cmpthese(10000, {
'a1' => sub { my @l = (0, @a1); },
'a2' => sub { my @l = (0, @a2); },
'a3' => sub { my @l = (0, @a3); },
'a4' => sub { my @l = (0, @a4); },
'a5' => sub { my @l = (0, @a5); },
'a6' => sub { my @l = (0, @a6); },
});
Results:
(warning: too few iterations for a reliable count)
Rate a6 a5 a4 a3 a2 a1
a6 17.6/s -- -90% -99% -100% -100% -100%
a5 185/s 952% -- -90% -99% -100% -100%
a4 1855/s 10438% 902% -- -90% -99% -100%
a3 17857/s 101332% 9545% 862% -- -91% -98%
a2 200000/s 1135940% 107920% 10680% 1020% -- -80%
a1 1000000/s 5680100% 540000% 53800% 5500% 400% --
Bonus question: If my assumptions are correct (i.e. 0, @strings
creates a new list), does replacing map
with reduce
make sense?
doesn't
0, @strings
create a new list
Not really. If you decompile the code, it's just one additional SVOP.
But you're measuring the wrong thing. The values are flattened and passed into the map
or reduce
subroutine in both cases!
The documentation is talking about what happens inside the subroutine. map
creates a list of as many input values and returns them, and then sum
takes the list and condenses it into a value. The return list is ephemeral and is not represented directly in the code. (This list passing is not that efficient, it could be made faster by using references.)
In contrast, in reduce
, there no such return list. reduce
only works on the input list of values and returns a single value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With