Perl - Splitting an array, and looping through its sub-arrays

arrays, perl

Solution

One way to do this is by using the built-in `splice` function:

my @names = qw(one two three four five six);
while (@names) {
    my @chunk = splice @names, 0, 2;
    say "@chunk";
}

Note that this will destroy the `@names` array; if that's a problem, make a copy of it first.

If you like, you could even encapsulate this in a function, like this:

sub chunk_map (&$@) {
    my $code = shift;
    my $n = shift;
    my @out;
    while (@_) {
        push @out, $code->(splice @_, 0, $n);
    }
    return @out;
}

Because of the prototype, you can use this very much like the built-in function `map`, except that it takes an extra second parameter giving the chunk size, and passes the chunk to the callback function in `@_` rather than in `$_`. You could use it e.g. like this:

chunk_map { say "@_" } 2, @names;

or even:

say "@$_" for chunk_map { [@_] } 2, @names;

Edit: To tell in advance how many chunks there will be, you can simply divide the length of the array by the chunk size and round it up. To tell how many chunks you've processed so far, the easiest way is probably to maintain a counter:

my @names = qw(one two three four five six);
my $n = 4;

my $chunks = int((@names + $n - 1) / $n);  # round @names / $n up
my $i = 0;
while (@names) {
    $i++;
    my @chunk = splice @names, 0, $n;
    say "chunk $i / $chunks: @chunk";
}

Or, using the `chunk_map` function given above:

my @names = qw(one two three four five six);

my $chunks = my @chunks = chunk_map { [@_] } 4, @names;
foreach my $i (1 .. @chunks) {
    my @chunk = @{ $chunks[$i-1] };
    say "chunk $i / $chunks: @chunk";
}

Problem

Say I have an array like the following in Perl: ``` @names = ("one", "two", "three", "four", "five", "six"); ``` I would like to loop through this array in sub-arrays ("chunks") of pre-defined size. More specifically, I would like to have a variable, e.g. `@chunk` within my loop that holds the corresponding sub-array in each iteration: ``` for ? { say @chunk; } ``` For example, if I use `2` as my sub-array/chunk size, we would iterate 3 times, and `@chunk` would hold the following values across the : ``` ("one", "two") ("three", "four") ("five", "six") ``` If I use `4` as my chunk size, it would iterate only twice, and `@chunk` would hold: ``` ("one", "two", "three", "four") ("five", "six") # Only two items left, so the last chunk is of size 2 ``` Are there any built-ins/libraries to do this easily in Perl?

Original source