Reputation: 55
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
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
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
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
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