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

Hi, I have an array with values as follows:

@array = qw (1 1 0 2 0 1 3 0 0 4 1 1)

I would like to group the elements in 3s and print them to a file on one line, comma seperated i.e.

1,1,0
2,0,1
3,0,0
4,1,1

Any help appreciated.
Thanks
Joe

Replies are listed 'Best First'.
Re: Group array in threes
by moritz (Cardinal) on Feb 02, 2009 at 13:02 UTC
Re: Group array in threes
by toolic (Bishop) on Feb 02, 2009 at 13:48 UTC
    Read up on the natatime function in the List::MoreUtils CPAN module. It does exactly what you want to do and has example code you can copy'n'paste. You'll have to adapt it to print out commas instead of whitespace between elements.
Re: Group array in threes
by Bloodnok (Vicar) on Feb 02, 2009 at 13:50 UTC
    Why not use splice ...
    while (@array) { print join(',', splice @array, 0, 3) . qq/\n/ }
    ... or some such?

    A user level that continues to overstate my experience :-))
Re: Group array in threes
by lakshmananindia (Chaplain) on Feb 02, 2009 at 13:21 UTC

    Here is the another way

    @arr = qw (1 1 0 2 0 1 3 0 0 4 1 1); for (0..@arr/3) { print $arr[3*$_],$arr[3*$_+1],$arr[3*$_ +2],"\n"; }
Re: Group array in threes
by kyle (Abbot) on Feb 02, 2009 at 13:10 UTC

    This is a sort of crude first crack at it to get you started. I haven't accounted for having an array that doesn't have some multiple of three elements.

    use 5.010; foreach my $n ( 0 .. $#array/3 ) { my $i = $n * 3; say join q{,}, @array[ $i, $i+1, $i+2 ]; }
Re: Group array in threes
by johngg (Canon) on Feb 02, 2009 at 14:50 UTC

    Another way using an on-the-fly subroutine which leaves the array untouched.

    use strict; use warnings; my @arr = qw{ 1 1 0 2 0 1 3 0 0 4 1 1 }; sub { local $" = q{,}; print qq{@{ [ map shift, 1 .. 3 ] }\n} while @_; }->( @arr ); print qq{@arr\n};

    The output.

    1,1,0 2,0,1 3,0,0 4,1,1 1 1 0 2 0 1 3 0 0 4 1 1

    If the array has an element count that is not a multiple of three then add a grep to avoid "Use of uninitialized value in join or string..." warnings.

    use strict; use warnings; my @arr = qw{ 1 1 0 2 0 1 3 0 0 4 1 1 5 7 }; sub { local $" = q{,}; print qq{@{ [ grep defined, map shift, 1 .. 3 ] }\n} while @_; }->( @arr ); print qq{@arr\n};
    1,1,0 2,0,1 3,0,0 4,1,1 5,7 1 1 0 2 0 1 3 0 0 4 1 1 5 7

    I hope this is of interest.

    Cheers,

    JohnGG

    Update: Fixed broken para tag.

    Also, looking at moritz's reply, I don't know why it never occurs to me to modify output field and record separators instead of list separator. Doing so makes things much cleaner.

    use strict; use warnings; my @arr = qw{ 1 1 0 2 0 1 3 0 0 4 1 1 5 7 }; sub { local( $,, $\ ) = ( q{,}, qq{\n} ); print grep defined, map shift, 1 .. 3 while @_; }->( @arr );
Re: Group array in threes
by fullermd (Vicar) on Feb 02, 2009 at 17:14 UTC
Re: Group array in threes
by JavaFan (Canon) on Feb 02, 2009 at 13:29 UTC
    { local $" = ","; my $_ = "@array"; s/([^,]*,[^,]*,[^,]*),/$1\n/g; print; }
Re: Group array in threes
by hbm (Hermit) on Feb 02, 2009 at 13:43 UTC

    You could keep a counter; and print each item followed by a comma if counter-mod-3, or by a newline otherwise:

    @array = qw (1 1 0 2 0 1 3 0 0 4 1 1); my $i; print $_, ((++$i%3)?",":"\n") for (@array);

    Update:

    Per your other question, If (and it may in future) contain references how can i print those and not ARRAY(0x860be48) etc?, ref is your friend:

    my $q = "Q"; my @p = qw(pee pea); my %h = ( one => 1, two => 2, three => 3); @array = ("1", \@p, "0", "2", "0", \$q, "2", "0", \%h, "4", "1", "1"); my $i; for my $a (@array) { $_ = ref($a); print ( /ARRAY/ ? join(':',@$a) : /HASH/ ? join(':',keys %$a) : /SCALAR/ ? $$a : $a ); print ((++$i%3) ? "," : "\n" ); }
Re: Group array in threes
by repellent (Priest) on Feb 02, 2009 at 17:18 UTC
    If all you care about is printing:
    my @array = qw(1 1 0 2 0 1 3 0 0 4 1 1); my $i = 1; for (@array) { print; print $i++ % 3 ? "," : "\n" } print "\n";
Re: Group array in threes
by jethro (Monsignor) on Feb 02, 2009 at 13:05 UTC
    This sounds like homework. Do yourself a favor and try to solve it yourself, otherwise your next test or exam will be a disaster. I'll give you two hints: Use a loop and take a look at the shift() function
      Homework - i wish! What the array actually contains is molecular statistics and pharmacokinetic results.

      If (and it may in future) contain references how can i print those and not ARRAY(0x860be48) etc?

      Thanks

        Here is a simple solution with arrayref and one that can cope with array sizes not having multiples of threes

        my $array= [1,2,3,4,5]; while (@$array) { push my @r, shift @$array if (@$array); push @r, shift @$array if (@$array); push @r, shift @$array if (@$array); print join(',',@r),"\n"; }