http://qs321.pair.com?node_id=639908

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

looks like i need help from the monks again :(
is there a function out there for perl array that enables me to split my array like every 5 elements? say like..
my @myArray = (1..100); my @myMainArray = (); my $c = 1; foreach (@myArray){ if(c++ = 5){ #1.some splitting occurs and assign to a 5 element array #2.push 5 element array into main array #3.reset c = 1; } }
then at the end i'll be able to construct a nested loop that could extract them out like
my @myArrayResult = @myMainArray; foreach my $o(@myArrayResult){ foreach my $i($o){ #print out } }

Replies are listed 'Best First'.
Re: how to seperate array after a certain number of elements?
by ikegami (Patriarch) on Sep 19, 2007 at 15:16 UTC

    splice can be used to extract elements from an array.

    my @myArray = (1..100); my @myMainArray; while (@myArray) { push @myMainArray, [ splice(@myArray, 0, 5) ]; } foreach my $record (@myMainArray) { print(join(', ', @$record), "\n"); }

    Update: Fixed typo bug in code. Thanks ww.

Re: how to seperate array after a certain number of elements?
by NetWallah (Canon) on Sep 19, 2007 at 15:35 UTC
    You could use a classic C-style loop, and array slicing:
    my @a=(0..12); # Admittedly, not the best choice for variable names... my @b; for (my $i=0; $i <= $#a; $i+=5) { push @b,join(',', @a[$i..$i+4]); print qq[ $i:$a[$i]=@b \n]; } # @b ends up with comma-separated, 5-element (or less for last chunk) + chunks of @a
    Update: This is NON-Destructive on @a, compared to the ikegami's solution above. Not that there is anything wrong with being destructive, if you know what you are doing.

         "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Re: how to seperate array after a certain number of elements?
by artist (Parson) on Sep 19, 2007 at 15:51 UTC
    Here is the iterator approach. ( N at a time)
    use List::MoreUtils qw(natatime); my @myArray = (1..100); my @myMainArray = (); my $chunkSize = 5; my $iterator = natatime $chunkSize, @myArray; while(my @values = $iterator->()){ push @myMainArray, [@values]; } foreach (@myMainArray){ my @smallArray = @{$_}; print "@smallArray\n"; }
    Here is a 'hacked' approach using 'part'.
    use List::MoreUtils qw(part); @array = (1..100); $i = -0.1; @parts = part { $i += 0.2 } @array;
    --Artist

      It's dangerous to repeatedly add decimal numbers since many of them are periodic in binary and therefore cannot be stored precisely. This includes 0.2.

      >perl -le"printf '%.17f', .2 0.20000000000000001

      The following is a safer, simpler and easier to read (since "5" actually appears) version of your second snippet:

      use List::MoreUtils qw(part); my @array = (1..100); my $i; my @parts = part { ($i++)/5 } @array;
        Thanks, I never knew the reason behind it. Very useful tip.
        --Artist
Re: how to seperate array after a certain number of elements?
by un-chomp (Scribe) on Sep 19, 2007 at 17:10 UTC
    Also non-destructively:
    my @myMainArray = map { [ $myArray[$_] .. $myArray[$_+4] ] } grep { !($_ % 5) } 0 .. $#myArray;
    That assumes the list has at least 5 elements and is exactly divisible by 5. Otherwise:
    my @myMainArray = map { exists $myArray[ $_+4 ] ? [ $myArray[$_] .. $myArray[$_+4] ] : [ $myArray[$_] .. $myArray[-1] ] } grep { !($_ % 5) } 0 .. $#myArray;
      That refactors nicely:
      my @myMainArray = map [ @myArray[$_ .. ($_+4 < $#myArray ? $_+4 : $#myArray)] ], map $_ * 5, 0 .. $#myArray/5;

      Caution: Contents may have been coded under pressure.
Re: how to seperate array after a certain number of elements?
by dwm042 (Priest) on Sep 19, 2007 at 15:54 UTC
    There is no built-in function, but I can give an example. Since you might need to break on different values, this is one place a solution based on a closure might be apt:

    #!/usr/bin/perl use warnings; use strict; my @data = ( 1,2,3,4,5,6,7,8,9,10,11,12 ); my @collection = (); my $break_5 = &break_by(5); $break_5->( \@data, \@collection ); for my $c (@collection) { print $_, " " for @{$c}; print "\n"; } sub break_by { my $count = shift; return sub { my ( $data_ref, $collection_ref ) = @_; my @temp = (); foreach (@{$data_ref}) { push @temp, $_; if ( @temp >= $count ) { push @{$collection_ref}, [@temp]; @temp = (); } } push @{$collection_ref}, [@temp] if (@temp); } }
    And the output is:

    C:\Code>perl close_and_break.pl 1 2 3 4 5 6 7 8 9 10 11 12
    Update: Tighter code
      Or you could go a step further and make an iterator.
      sub break_by { my ($by, $data) = @_; my $i = 0; return sub { my $n = @$data - $i; $n = $n < 0 ? 0 : $n > $by ? $by : $n; $i += $n; return @$data[$i-$n..$i-1]; } } my @data = ( 1,2,3,4,5,6,7,8,9,10,11,12 ); my $iter = break_by(5, \@data); while (my @group = $iter->()) { print("@group\n"); }
Re: how to seperate array after a certain number of elements?
by hangon (Deacon) on Sep 20, 2007 at 04:13 UTC

    Here's another nondestructive method using array slices.

    use strict; use warnings; my @myArray = (1..100); my @myMainArray = (); my $i = 0; while ($i < scalar @myArray){ push (@myMainArray, [@myArray[$i .. $i+4]]); $i += 5; }
Re: how to seperate array after a certain number of elements?
by adrive (Scribe) on Sep 20, 2007 at 02:46 UTC
    thanks guys!! you really saved my day :)
Re: how to seperate array after a certain number of elements?
by princepawn (Parson) on Sep 20, 2007 at 19:19 UTC
    Array::Group


    Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality
Re: how to seperate array after a certain number of elements?
by smokemachine (Hermit) on Sep 20, 2007 at 21:27 UTC
    try this (destructive):
    perl -e '@a=1..100;while(@a){push@b,[@a[0..4]];@a=@a[5..$#a];}'