Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

A classic use of prototypes: map2

by tkil (Monk)
on May 02, 2004 at 04:50 UTC ( #349747=perlmeditation: print w/ replies, xml ) Need Help??

Prototypes in perl5 have gotten a bit of a bad reputation, some of which is deserved. If people ask me why we should use them at all, however, I do have an example that always respond with map2, which is like the built-in map except that it accepts two arrays as arguments (instead of a single list).

=item my @result = map2 BLOCK ARRAY, ARRAY; Similar to c<map>, but operate on two lists at once. Inside the BLOCK, the value are passed in as C<$a> and C<$b> (as in C<sort>). my @a = ( 1, 2, 5, 7, ); my @b = ( 3, 4, 6, 8 ); my @sums = map2 { $a+$b } @a, @b; my @prods = map2 { $a*$b } @a, @b; One use is to initialize hashes from two arrays. You can do this in straight perl with: my %hash; @hash{@hash_keys} = @values; With this subroutine, you could also do: my %hash = map2 { ( $a => $b ) } @hash_keys, @values; If the arrays are not the same length, the shorter array is used to limit how far we go in each array. BLOCK is evaluated in list context. =cut sub map2 ( & \@ \@ ) { my ( $code_ref, $a_ref, $b_ref ) = @_; my $rv_len = ( @$a_ref < @$b_ref ) ? @$a_ref : @$b_ref; my @rv; for ( my $i = 0; $i < $rv_len; ++$i ) { local ( $a, $b ) = ( $a_ref->[$i], $b_ref->[$i] ); push @rv, $code_ref->(); } return @rv; }

I know I saw something like this from Abigail (or is that Abigail-II?) in the late '90s, but I have since reimplemented it a few times. As I said, it serves as a handy example to demonstrate how prototypes make some things possible that would otherwise be difficult to impossible to code.

Update (2004-05-02 00:15 -0700): Incorporated some suggestions from Zaxo to fix some misleading variable names. Thanks!

Comment on A classic use of prototypes: map2
Select or Download Code
Re: A classic use of prototypes: map2
by Zaxo (Archbishop) on May 02, 2004 at 05:47 UTC

    Shouldn't $max_index be $min_index and look like this?

    my $min_index = @$a_ref < @$b_ref ? $#$a_ref : $#$b_ref;
    There is no need to localize or subvert $a and $b. Just make the coderef act on $_[0] and $_[1] or their lexical copies.

    After Compline,
    Zaxo

      Shouldn't $max_index be $min_index

      Well, it's the minimum of the two indexes ... but it's the maximum value that the loop counter runs to. I was apparently thinking of the latter when I named the variable. Suggestions on a better name are welcome. (Maybe $shortest_array_len, which is closer in spirit to your suggestion as well as describing its role in the loop...)

      There is no need to localize or subvert $a and $b. Just make the coderef act on $_[0] and $_[1] or their lexical copies.

      My original code did exactly that... but I found myself using $a and $b anyway. And since perl exempts them from use strict checking, it would always take me a while to figure out what was going wrong.

      For the record, the original that I spruced up a bit:

        You get trouble with undefined quantities if you go beyond the minimum last index. Your updated code still uses @$arrayref instead of $#$arrayref as the last index of the referenced array.

        After Compline,
        Zaxo

Re: A classic use of prototypes: map2
by Errto (Vicar) on May 02, 2004 at 18:54 UTC

    I'm a big fan of this sort of thing. In fact my other favorite programming language, Haskell, has a built-in function called "zipWith" that does precisely this. Combined with lazy operators, this lets you do things like define the Fibonacci sequence:

    fib = 1 : 1 : zipWith (+) fib (tail fib)

    where (+) is equivalent to your {$a+$b}, ":" is how you say "cons" or, arguably, unshift, and "tail" is how you say "cdr" or, arguably, @foo[1 .. $#foo], but without necessarily making a copy.

      I'm a big fan of this sort of thing. In fact my other favorite programming language, Haskell

      I do a little bit of functional programming (mostly emacs-lisp, of all things), but I do enjoy it. Did you see tye's mention of his module Algorithm::Loops? If you like the functional style, that looks like some good stuff in there.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://349747]
Approved by b10m
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2015-07-02 22:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (46 votes), past polls