Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re^5: Fold a list using map splices

by hypochrismutreefuzz (Scribe)
on Sep 04, 2004 at 01:38 UTC ( #388461=note: print w/replies, xml ) Need Help??


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

You're both inspirational, guys++. However, it seems to me that you ought to put the padding at the end of the array; with the exception being that if the number of columns divides the length of the array with no remainder then you don't add the padding.

Also I think that the splice on each iteration is wasteful, so I'll just change the indexes so that each row comes out correct.

sub map_nbsp (&@) { my ($codeblock, $cols) = splice @_, 0, 2; splice @_, @_, 0, (' ')x$cols if @_ % $cols; my $rows = int @_/$cols; map{ $codeblock->(@_[$cols*$_ .. $cols*($_+1)-1]); } 0 .. ($rows)-1; } my @tabular_data = map{ 1000+int rand 8999 } 1 .. 9; print table( {border=>1}, map_nbsp{ Tr( td( \@_ ) ); } 4, @tabular_data );

Replies are listed 'Best First'.
Re^6: Fold a list using map splices
by Aristotle (Chancellor) on Sep 04, 2004 at 03:01 UTC

    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.

      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://388461]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (6)
As of 2021-03-03 15:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My favorite kind of desktop background is:











    Results (80 votes). Check out past polls.

    Notices?