Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re^4: Fold a list using map splices

by Aristotle (Chancellor)
on Feb 22, 2003 at 15:24 UTC ( [id://237747]=note: print w/replies, xml ) Need Help??


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

I was pretty sure yours would be quicker - but by how much is that?

Thanks for the heads up on the one-off error..

Makeshifts last the longest.

Replies are listed 'Best First'.
Re^5: Fold a list using map splices
by hypochrismutreefuzz (Scribe) on Sep 04, 2004 at 01:38 UTC

    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 );

      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
Re: Re^4: Fold a list using map splices
by BrowserUk (Patriarch) on Feb 22, 2003 at 21:09 UTC

    About 15% on average. Hardly worth worrying about in the scheme of things.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (None)
    As of 2024-04-25 01:03 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found