3

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.

8
  • 2
    WHat 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,1 Commented 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. Commented 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? Commented 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. Commented May 28, 2011 at 11:43
  • natatime Commented May 28, 2011 at 14:08

4 Answers 4

8

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. 
Sign up to request clarification or add additional context in comments.

Comments

5

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;

Comments

1

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;

Comments

1

@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;
    };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.