spandox has asked for the wisdom of the Perl Monks concerning the following question:

I have a solution - but I want a more clever way to do it.
sub doubleStack { my $count = pop; my @out; while (@_){push @out, [splice @_,0,$count];} return @out; }
What it does: Give it an array and a length - and it returns and array of arrays where each sub array is length long.
doubleStack(qw(a b c e 1 2 3 4 5 3 f),3) returns: $VAR1 = [ [ 'a', 'b', 'c' ], [ 'e', '1', '2' ], [ '3', '4', '5' ], [ '3', 'f'] ];
It would be fun to be able to do this in-line without a sub. BTW - I use this for generating multi-line output - tables and such. Anyone have a cool way to do this?

Replies are listed 'Best First'.
Re: stack array to array of arrays
by Kenosis (Priest) on Oct 16, 2013 at 19:20 UTC

    List::MoreUtils offers a similar functionality:

    use strict; use warnings; use List::MoreUtils qw/natatime/; my @array = qw(a b c e 1 2 3 4 5 3 f); my $it = natatime 3, @array; while ( my @vals = $it->() ) { print "@vals\n"; }

    Output:

    a b c e 1 2 3 4 5 3 f

    BTW - I use this for generating multi-line output...

    Here's another option for multi-line output (generated from a single line):

    use strict; use warnings; use Text::Wrap; $Text::Wrap::columns = 18; my $text = <<END; BTW - I use this for generating multi-line output - tables and such. END print wrap(" ", '', $text);

    Output:

    BTW - I use this for generating multi-line output - tables and such.

    Hope this is helpful.

Re: stack array to array of arrays
by johngg (Canon) on Oct 16, 2013 at 21:54 UTC

    Using a subroutine that takes a code block as its first argument and applies that code to groups of size specified in the second argument taken from the remaining arguments.

    use strict; use warnings; use Data::Dumper; sub groupsOf (&$@); my $doubleStack = [ groupsOf { [ @_ ] } 3, qw{ a b c e 1 2 3 4 5 3 f } ]; print Data::Dumper ->Dumpxs( [ $doubleStack ], [ qw{ doubleStack } ] ); sub groupsOf (&$@) { my $rcToRun = shift; my $groupsOf = shift; my $rcDoIt; $rcDoIt = sub { $rcToRun->( map shift, 1 .. ( @_ < $groupsOf ? @_ : $groupsOf ) ), @_ ? &$rcDoIt : (); }; &$rcDoIt; }

    The output.

    $doubleStack = [ [ 'a', 'b', 'c' ], [ 'e', '1', '2' ], [ '3', '4', '5' ], [ '3', 'f' ] ];

    I hope this is of interest.

    Cheers,

    JohnGG

Re: stack array to array of arrays
by hdb (Monsignor) on Oct 16, 2013 at 18:55 UTC

    This works but it is not cool...

    use strict; use warnings; use Data::Dumper; my @array = qw(a b c e 1 2 3 4 5 3 f); my $len = 3; my @stack = map{$_%$len?():[grep{$_}@array[$_..$_+$len-1]]} 0..@array- +1; print Dumper \@stack;

    ...or this...a destructive version...

    @array = map { [ map { shift @array//() } 1..$len ] } 0..int((@array-1)/$len);
      the
      grep{$_} .......
      also removes "" and 0 from the list. Should probably be
      grep{defined $_} .....
      Also - why use
      @array -1
      when you could use
      $#array
      I like the approach.... Perhaps
      map{[ grep {defined} @array[$_*$len..$_*$len+$len-1] ]} 0..$#array/$len
      Is a little cleaner?
Re: stack array to array of arrays
by kcott (Archbishop) on Oct 17, 2013 at 04:24 UTC

    G'day spandox,

    Not recommended for production code. :-)

    #!/usr/bin/env perl use strict; use warnings; use Data::Dump; my @a = qw{a b c e 1 2 3 4 5 3 f}; my $x = 3; dd [(map{@;==$x?do{$;=[@;];@;=($_);$;}:do{push(@;,$_);()}}@a),[@;]];

    Output:

    [["a", "b", "c"], ["e", 1, 2], [3, 4, 5], [3, "f"]]

    [P.S. With "my @a = ();", the output is "[[]]".]

    -- Ken

Re: stack array to array of arrays
by LanX (Saint) on Oct 16, 2013 at 22:12 UTC
    > It would be fun to be able to do this in-line without a sub

    DB<119> @a=a..e => ("a", "b", "c", "d", "e") DB<120> map [splice @a,0,3], 0..$#a/3 => (["a", "b", "c"], ["d", "e"])

    but beware of the case @a=()

    > Anyone have a cool way to do this?

    not really :(

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      I like this because it is small - HOWEVER it is destructive of the original array. It does often work for me though. in my code it looks like
      my @array = qw(0 a b c e 1 2 3 4 5 3 f w); my $len = 4; print oxTable->new([ map [splice @array,0,$len], 0..$#array/$len ]);
      Produces
      +--+--+--+--+ |0 |a |b |c | |e |1 |2 |3 | |4 |5 |3 |f | |w | | | | +--+--+--+--+
        > I like this because it is small

        I don't like it, IMHO it's

        1. hard to read golfing!
        2. not DRY
        3. and furthermore buggy in edge cases.

        you might get used to it, but the next one to maintain your code wont be "pleased".

        > It does often work for me though.

        Look! If you need it often, so why don't you just use your custom routine?

        Just compare the overhead to document this hack with just encapsulating all the infos in a sub!

        Or use something from List::MoreUtils ?

        DB<117> use List::MoreUtils qw/part/; DB<118> my $i; part {$i++ %3} a..h => (["a", "d", "g"], ["b", "e", "h"], ["c", "f"]) DB<119> use feature 'state'; part {state $i++ %3} a..h => (["a", "d", "g"], ["b", "e", "h"], ["c", "f"])

        update

        oops sorry, this transposed the matrix, corrected code:

        DB<139> use feature "state"; part {state $i++/3} a..h => (["a", "b", "c"], ["d", "e", "f"], ["g", "h"])

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: stack array to array of arrays
by roboticus (Chancellor) on Oct 17, 2013 at 12:14 UTC

    spandox:

    The best I came up with is:

    my @t = (qw( a b c e 1 2 3 4 5 3 f )); my $len = 3; my @u = map {[ @t[$_ .. $_+$len-1] ]} grep {!($_%$len)} 0 .. $#t;

    Fairly clear, but there's really no point in not using a well-named subroutine.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: stack array to array of arrays
by Random_Walk (Prior) on Oct 17, 2013 at 13:25 UTC

    Just for fun

    perl -MData::Dumper -lE "@r=(1..40);$s=5;$n[($i-$i%$s)/$s][$i++%$s]=$r[$i]for@r;say Dumper\@n

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!