HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Break an array into n equal or almost-equal sized sublists

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
sublistsarrayintoequalalmostsizedbreak

Problem

I want to break a larger list into $num-lists smaller lists. I thought that there might be an option for rotor that would already do it, but I haven't found one.

#!/bin/env perl6

my @a = 1 .. 13;

my @lists = fair-lists(@a, 3);

say @$_ for @lists;

sub fair-lists ( @array, $num-lists )
{
    my $num-elements = @array.elems;
    my $num-large    = $num-elements % $num-lists; # remainder
    my $num-small    = $num-lists - $num-large;

    my $small-size = floor($num-elements/$num-lists);
    my $large-size = $small-size + 1; # same as ceiling($num-element/$num-lists);

    my $first-large = ($num-small * $small-size);
    my $last-small  = $first-large - 1;

    my @first-sublist  = @array[ 0 .. $last-small];
    my @second-sublist = @array[ $first-large .. $num-elements - 1 ];

    my @small-lists = @first-sublist.rotor($small-size);
    my @large-lists = @second-sublist.rotor($large-size);
    my @all-lists   = (@small-lists, @large-lists).flat;
    return @all-lists;
}


Is there a more concise and more clear way to do this in Perl 6?

Solution

Using roundrobin on a rotored array works

sub fair-lists ( @array, Int $num-lists ) {

# "invert" the following "matrix"
roundrobin

# make it at least $num-lists long
|@array[{ 0 ..^ ( $_ max $num-lists ) }]\

# split it into chunks that are as big as the number of $num-lists
.rotor: $num-lists, :partial

}


say fair-lists( 1..1, 3 ).perl;
# ((1,), (Any,), (Any,)).Seq

say fair-lists( 1..4, 3 ).perl;
# ((1, 4), (2,), (3,)).Seq


test it

Context

StackExchange Code Review Q#119098, answer score: 5

Revisions (0)

No revisions yet.