1: # This function works like map, except it produces a single scalar
2: # output. It hence maps an array into a scalar hence the (clumsy)
3: # name scalarmap
4: #
5: # It requires 3 parameters
6: # 1) A code block like map. This will be passed $a and $b
7: # $a will be the result and $b is the current element
8: # it should return the new result
9: # 2) An initial value
10: # 3) An array
11:
12: sub scalarmap (&$@)
13: {
14: my $code = shift;
15: local ($a, $b) = ( shift );
16: foreach $b (@_)
17: {
18: $a = &$code;
19: }
20: return $a;
21: }
22:
23: # Here are some examples
24:
25: my @array = 1..10;
26:
27: my $sum = scalarmap { $a + $b } 0, @array;
28:
29: my $sum_of_even_numbers = scalarmap { $b & 1 ? $a : $a + $b } 0, @array;
30:
31: my $factorial = scalarmap { $a * $b } 1, @array;
32:
33: my $fancy_join = scalarmap { $a . $b } "", 'a'..'z';
34:
35: # I don't suppose this will be actually useful in real life but it
36: # amused me to make a twist an the all powerful map!
37: #
38: # This was inspired by a reference kudra made to subroutines and man
39: # perlsub.
RE: scalarmap - some new perl syntax
by btrott (Parson) on Sep 01, 2000 at 02:26 UTC
|
This is fun to play with. A few comments:
- You wrote:
my $fancy_join = scalarmap { $a . $b } "", 'a'..'z';
This isn't doing what you think it is. If "" is the initial
element, it's not going to be used to join each of the
elements together into a string. Well, it's not going to
do so as join would do it, at least. Try it with something
like ", " to see.
In case you don't feel like trying it, here's the results
of:
print scalarmap { $a . $b } ", ", 'a'..'z';
, abcdefghijklmnopqrstuvwxyz
- I'm not sure I like the use of $a and $b. That's
too reminiscent of sort, where the elements are
"equivalent" in terms of their relation to each other;
they're both elements in the list, in other words.
Here, though, $a is actually the *total* of whatever
has come before in the list, where "total" means
whatever you've defined it to mean in your code
reference. And $b is just a lowly element. :)
So they're not on the same "level" of meaning as it
were. I like using $_ inside of map blocks. If it were
me, I'd change $b to $_, and $a to something
special and local, like $T, for total, or something
like that. I don't know.
- This is just getting snippy :), but I don't like having
the initial value being the parameter following the
code block. Because the code block is "acting" on
the list, so it makes sense to follow the code block
with the list.
Maybe move the inital value in front of the code block?
Anyway, I like this. Thanks for posting it. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
scalarmap { $_->[0] + $_->[1] } 0, @z;
But that isn't as elegant.
I considered using $a and $_ but that offended me too!
I see from merlyn's post below that the maker of List::Util::reduce came to the same conclusions... | [reply] [Watch: Dir/Any] [d/l] |
|
You are quite right about the join thing! I just wanted an example with a string and I didn't intend it to be a full blown join replacement!
See my reply to tilly for $a and $b.
I agree with you about having the initial value first, but
I couldn't get it to work. Trying to prototype the subroutine as ($&@) meant that I couldn't call it for some
reason.
If I try this :-
sub scalarmap ($&@)
{
local ($a, $b) = ( shift );
my $code = shift;
foreach $b (@_)
{
$a = &$code;
}
return $a;
}
my @array = 1..10;
my $sum = scalarmap 0, { $a + $b } @array;
Then when I run it I get
Array found where operator expected at scalarmap2.pl line 32, near "
+} "
(Missing operator before ?)
syntax error at scalarmap2.pl line 32, near "} @array"
Which is puzzling... | [reply] [Watch: Dir/Any] [d/l] [select] |
RE: scalarmap - some new perl syntax
by merlyn (Sage) on Sep 01, 2000 at 10:04 UTC
|
What a great idea. In fact, it's so great, it's already been implemented (in C, with
a fallback to Perl if the C fails to load) at List::Utils under the name
reduce.
And the reduce operator is one of the ideas to add into Perl6, so eventually
we won't even need to get into a module. {grin}
Something tells me that there isn't enough searching of the existing cool stuff
in the CPAN going around. {grin}
-- Randal L. Schwartz, Perl hacker | [reply] [Watch: Dir/Any] |
|
I might have known that there would be a CPAN thingy to
do it, and that merlyn would know of it {grin} ;-)
Reduce is a much better name. It calls your sub with $a
and $b set to the first two elements of the array which
is neater in some ways, but would make it harder to write
the factorial example above.
Here is a related question - I tried to write the
subroutine above with the paramters ($&@) but I couldn't
then call the subroutine - looks like a bug... (I posted an example of this a bit further up the thread)
BTW it is List::Util
| [reply] [Watch: Dir/Any] |
|
> It calls your sub with $a and $b set to the first two
> elements of the array which is neater in some ways,
> but would make it harder to write the factorial example
> above.
How so? Your initial value is, in this case, really just the first
element of the array, in the case of reduce (I didn't realize
this until looking at reduce, granted). So you'd just make your
array 1..$N for a factorial. Like this:
sub factorial {
reduce { $a * $b } 1..$_[0]
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|