Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Re^6: Fold a list using map splices

by Aristotle (Chancellor)
on Sep 04, 2004 at 03:01 UTC ( #388475=note: print w/replies, xml ) Need Help??


in reply to Re^5: Fold a list using map splices
in thread Fold a list using map splices

I'm not sure why I used splice where I could have used unshift. Probably for the same reason you used it instead of push — too fixated on splicing. :-)

You misunderstood the purpose of the padding in my code, btw. Remember that I splice before invoking the callback — which means that without padding, I'd be throwing away the values that should have been processed in the first iteration. I'm unsure what kind of pretzel logic led me to that solution, I should simply have used the list returned from splice.

sub mapn (&@) { my ( $callback, $n ) = splice @_, 0, 2; map $callback->( splice @_, 0, $n ), 0 .. @_ / $n -1; }

One thing about your solution that irks me since my days as an assembler programmer is multiplying a constant with a counter in a loop. You get the same effect if you simply iteratively add the constant to a counter. Of course, it doesn't make a particular difference in efficiency in Perl, but I find that it can still improve clarity and reduce repetition to do it that way.

sub mapnz (&@) { my ( $callback, $n ) = splice @_, 0, 2; my ( $i, $j ) = ( 0 ) x 2; map { $i = $j; $callback->( @_[ $i .. ( $j += $n ) - 1 ] ); } 0 .. @_ / $n - 1; }

As well, the non-padding case can be dealth with less cumbersomely than my and BrowserUk's previous attempts do, which rely on that really ugly ternary.

The splicing flavour (see 2nd update):

sub mapn (&@) { my ( $callback, $n ) = splice @_, 0, 2; map { $n = @_ if $n > @_; $callback->( splice @_, 0, $n ); } 0 .. @_ / $n - 1; }

Analogously, the index-based flavour:

sub mapn (&@) { my ( $callback, $n ) = splice @_, 0, 2; my ( $i, $j ) = ( 0 ) x 2; map { $i = $j; $n = @_ - $i if $i + $n > @_; $callback->( @_[ $i .. ( $j += $n ) - 1 ] ); } 0 .. @_ / $n - 1; }

I think I'd still prefer the splicing version.

Update: the index-based flavour had $n = $#_ - $i if $i + $n > $#_; which is an off-by-one error, since the range goes to ( $j += $n ) - 1. It has indeed got to be completely analogous to the splicing flavour, using @_ instead. Fixed.

Update: I am amused at myself. The "padding" splicing version actually didn't pad, because splice, of course, only returns as many elements as there are left, if you ask for more. The padding version turns out to be much simpler than the "non-padding" version I concocted before — no special cases at all!

sub mapnz (&@) { my ( $callback, $n ) = splice @_, 0, 2; push @_, ( undef ) x ( -@_ % $n ); map $callback->( splice @_, 0, $n ), 0 .. @_ / $n - 1; }

This is Perl as I love it. Beautiful and simple. :-)

Makeshifts last the longest.

Replies are listed 'Best First'.
Re^7: Fold a list using map splices
by hypochrismutreefuzz (Scribe) on Feb 20, 2006 at 14:02 UTC

    I wonder if its even necessary to have a callback function.

    package HTML::Table; use CGI; my $cgi = CGI->new(); sub map_rows (@) { my $n = splice(@_, 0, 1); push(@_, '' x (-@_ % $n)); my @table_rows = map {$cgi->Tr( $cgi->td( [splice @_, 0, $n] ) ) } 0..((@_/$n) - 1); } sub make_table { my ($columns, @elements) = @_; return $cgi->table( map_rows $columns, @elements ); } 1;

    And the testing code

    use HTML::Table; my $table = HTML::Table::make_table(5, qw[some random data to test th +e table creation thing] ); print $table;

    Output

    <table><tr><td>some</td> <td>random</td> <td>data</td> <td>to</ td> <td>test</td></tr> <tr><td>the</td> <td>table</td> <td>creation</t +d> <td>thing</td> <td></td></tr></table>

    Or perhaps

    some random data to test
    the table creation thing

      The callback is not necessary; you can translate anything written with map to foreach. I still prefer map for a whole class of tasks, though.

      Makeshifts last the longest.

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $SPLITSIZE = 1 + int rand(6); my $len = int rand(20); printf "SPLITSIZE=%d, len=%d\n", $SPLITSIZE, $len; my @list = 1..$len; @list = map[splice @list, 0, $SPLITSIZE], 0..$#list/$SPLITSIZE; print Dumper(\@list);

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (7)
As of 2021-02-24 18:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?