user774234
user774234

Reputation: 55

Perl - Split Array in to Smaller Evenly Distributed Arrays

How would I split a Perl array of arbitrary size in to a variable number of smaller arrays with the number of elements in each smaller array being distibuted as evenly possible? The original array must not be destroyed.

Upvotes: 3

Views: 6659

Answers (4)

Mike Fox
Mike Fox

Reputation: 11

@Dallaylaen's answer doesn't quite work because you can't pass an array into a subroutine in Perl. Instead of passing in an array (or a list as Dallaylaen did in his example) you must pass in a reference to an array:

    my @arrayIn = (1..30);
    my @arrayOfArrays = distribute(7, \@arrayIn);
    sub distribute {
        my ($n, $array) = @_;

        my @parts;
        my $i = 0;
        foreach my $elem (@$array) {
            push @{ $parts[$i++ % $n] }, $elem;
        };
        return @parts;
    };

Upvotes: 1

joehep
joehep

Reputation: 154

If you don't care what winds up in each array:

use strict;
use warnings;

use List::MoreUtils qw(part);
use Data::Dumper;

my $i = 0;
my $numParts = 2;
my @part = part { $i++ % $numParts } 1 .. 30; 
print Dumper @part;

Upvotes: 1

Tim Retout
Tim Retout

Reputation: 182

Here's a version using List::MoreUtils:

use strict;
use warnings;

use List::MoreUtils qw(part);

use Data::Dumper;

my @array = 1..9;
my $partitions = 3;

my $i = 0;

print Dumper part {$partitions * $i++ / @array} @array;

Upvotes: 5

Dallaylaen
Dallaylaen

Reputation: 5308

Off the top of my head:

use strict;
use warnings;

use Data::Dumper; # for debugging only 

print Dumper(distribute(7, [1..30]));

# takes number+arrayref, returns ref to array of arrays
sub distribute {
    my ($n, $array) = @_;

    my @parts;
    my $i = 0;
    foreach my $elem (@$array) {
        push @{ $parts[$i++ % $n] }, $elem;
    };
    return \@parts;
};

This guarantees that number of elements in @parts may only differ by one. There's anonther solution that would count the numbers beforehand and use splicing:

push @parts, [ @$array[$offset..$offset+$chunk] ];
$offset += chunk;
# alter $chunk if needed. 

Upvotes: 8

Related Questions