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.
-
2WHat does "as evenly as possible" mean? An array of size 11 could be split into 5,6 or 4,4,3 or 2,2,2,2,2,1user485498– user4854982011-05-28 11:08:12 +00:00Commented May 28, 2011 at 11:08
-
It means exactly what you posted in the examples you gave. The first if 2 arrays are required, the second if three arrays are required and the last one if six arrays are required.user774234– user7742342011-05-28 11:12:36 +00:00Commented May 28, 2011 at 11:12
-
Here may be useful: stackoverflow.com/questions/1490896/… As to my above point. You have to decide how to split up the array i.e. 4,4,3 4,3,4 or 3,4,4. Does it matter which way?user485498– user4854982011-05-28 11:39:49 +00:00Commented May 28, 2011 at 11:39
-
The size of the array is always a factor of 3 in that example rather than an arbitrary sized array. It does not matter which way the array is split up.user774234– user7742342011-05-28 11:43:56 +00:00Commented May 28, 2011 at 11:43
-
natatimedaxim– daxim2011-05-28 14:08:13 +00:00Commented May 28, 2011 at 14:08
|
Show 3 more comments
4 Answers
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.
Comments
@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;
};