Revelation has asked for the wisdom of the Perl Monks concerning the following question:
Under this pretense, this morning I wrote something that roughly looked like ({grin} I'm not using map in a void context, by the way ):%hash = (); foreach $_ (@array) { $hash{getkey($_)} = $_; }
which I assumed, in accordance with perldoc, would roughly translate to:my %res = map { $_ => do { my $re; $re .= $translations{$_} for split //; $re; } if !$res{$_}; } @words;
Obviously this isn't a literal translation, but that's unimportant right now. What confused me was that Perl threw an error (using strict), telling me that I needed to define %res in the line: } if !$res{$_}; Thus, adding a my %res to the beginning of my map code solved that problem. This was indicative of a larger problem, however; when benchmarking the two hash generations, it became rather obvious that Perl wasn't checking to see if that key already existed in my hash:my %res; foreach my $word (@rw) { $res{$word} ||= do { my $re; $re .= $translations{$_} for split //,$word; $re; } }
upon investigation, it turns out that when inside map, you can not refer to the array (or hash) you are assigning to at all:Benchmark: running foreach, map_it for at least 5 CPU seconds... foreach: 6 wallclock secs ( 5.34 usr + 0.00 sys = 5.34 CPU) @ 28 +6.87/s (n=1531) map_it: 5 wallclock secs ( 5.15 usr + 0.01 sys = 5.16 CPU) @ 13 +4.77/s (n=695)
simply throws an error, because $a[0] will return undefined until the map call is completed. As far as I can tell this behavior is not documented and unexplainable. Perl -MO=Deparse did not provide any explanation either. I have always been under the impression that map assigns to a list, like foreach does, but this doesn't seem to be true. In truth, judging from my experiences as well as the form of a map call, map returns a list that the array or hash you have created is _then_ set to.my @b = (7,5,5,6); my @a; @a = map { $_ > 5 ? $_ : $a[0] } @b;
|
|---|