20071101

Multi-Argument map For perl

I've been playing with perl recently. I avoiding the language for a long time because I hit python first and foolishly believed the hoards when they decried everything about perl. It can be cryptic, but perl is far from being without merit.

One of the things that kept bugging me when programming in perl was that there was the lack of a multi-argument grabbing map. I'd want to chain against the values of a hash and found annoyingly that the syntax was unhelpful.

A hash in list context dumps its keys and values into a zipped list.

{ 'k1' : 'v1' , 'k2' : 'v2 , 'k3' : 'v3' } -> [ 'k1' , 'v1' , 'k2' , 'v2' , 'k3' , 'v3' ]

This pretty much screws any sane sort of action that can be taken against the data. So instead you have to use `keys' to get a list of just keys in a `for' statement and then use the keys to access members of the hash.

I didn't really appreciate this restriction, as it meant I couldn't easily massage data with an anonymous function by mapping a sub block across it.

Thus was born mapper.

mapper takes three arguments. well, this being perl it takes one huge list of arguments. But it treats them like (defun mapper ( n f &rest L ) ... ) where


  • n : the number of elements to peel off of the list and hand to the sub function

  • f : a sub function

  • L : the list of items



It isn't long.


sub mapper
{
# n - number of items to pass at a time to the subroutine
# s - the subroutine
# r - the list of things to chunk and pass to the subroutine
# x - number of items to chunk
# c - index
# l - mapped values

local @_ = @_ ;

my ( $n , $s , @r ) = @_ ;
my $x = @r ;
my $c = 0 ;
my @l ;

while( $x > $c )
{
push @l , &$s( @r[ $c .. ( ( $c + $n ) - 1 >= $x ? $x - 1 : ( $c + $n ) - 1 ) ] ) ;
$c += $n ;
}

return @l ;

}


From this I derived a quick transposition function just to play with it ( demonstrating its use )


sub transpose
{
local @_ = @_ ;
mapper 2 , sub { ( $_[1] , $_[0] ) } , @_ ;
}


The function is rather obfuscatory when nested ...


print join ' ' , mapper 3 , sub { '<' . ( join '' , mapper 1 , sub { '[' . $_[0] . ']' } , @_ ) . '>' } , qw( the quick brown fox jumped over the lazy brown dog ) ;
print "\n" ;


You'll see from the last that mapper when presented with fewer than the expected number of items at the end of a list just passes along what it has, which is likely unhelpful for debugging, but helpful for applying n-arary functions across lists.

No comments:

About Me

(2) the subculture of the compulsive programmer, whose ethics prescribe that one silly idea and a month of frantic coding should suffice to make him a life-long millionaire. --ewd1036