Perl Weekly Challenge 373: List Division

by Abigail

Challenge

You are given a list and a non-negative integer.

Write a script to divide the given list into given non-negative integer equal parts. Return -1 if the integer is more than the size of the list.

Examples

Input:  @list = (1,2,3,4,5), $n = 2
Output: ((1,2,3), (4,5))

Input:  @list = (1,2,3,4,5,6), $n = 3
Output: ((1,2), (3,4), (5,6))

Input:  @list = (1,2,3), $n = 2
Output: ((1,2), (3))

Input:  @list = (1,2,3,4,5,6,7,8,9,10), $n = 5
Output: ((1,2), (3,4), (5,6), (7,8), (9,10))

Input:  @list = (1,2,3), $n = 4
Output: -1

Input:  @list = (72,57,89,55,36,84,10,95,99,35), $n = 7;
Output: ((72,57), (89,55), (36,84), (10), (95), (99), (35))

Input/Output

We prefer to take our input not as arrays or scalar variables, but to read it from standard input — where each line corresponds with an excercise. Our input consists of numbers separated by white space, where the first number equals the $n above.

So, the input corresponding to the examples above is as follows:

2 1 2 3 4 5
3 1 2 3 4 5 6
2 1 2 3
5 1 2 3 4 5 6 7 8 9 10
4 1 2 3
7 72 57 89 55 36 84 10 95 99 35

We output the sets with the elements separated by a space, and each set terminated by a semi-colon. So, the output with when given the input above will be

1 2 3; 4 5;
1 2; 3 4; 5 6;
1 2; 3;
1 2; 3 4; 5 6; 7 8; 9 10;
-1;
72 57; 89 55; 36 84; 10; 95; 99; 35;

Solution

To solve this exercise, for each line of input, we do the following steps:

Perl

With a line of input in $line, we start off by splitting it into the number of wanted subsets ($n) and the list of elements (@list):

my ($n, @list) = split /\s+/ => $line; 

Then we check whether we have enough elements in the list — if not, we print -1; and continue:

do {say "-1;"; next} if $n > @list;

Next, we calculate the minimum amount of element each set gets, and how many sets get one more element:

my $per_set  = int (@list / $n);
my $overflow = @list - $n * $per_set;

Iterate over the number of wanted sets, and calculate how many elements it gets:

for my $i (1 .. $n) {
    my $set_size = $per_set;
    $set_size ++ if $i <= $overflow;

Finally, print the set, and terminate it with a semi-colon:

print join " " => splice @list, 0, $set_size;
print "; ";

Find the full program on GitHub.

We also have solutions in AWK, Bash, bc, C, Lua, Go, Node.js, Python, R, Ruby, and Tcl, all following the same algorithm as the Perl solution.


Please leave any comments as a GitHub issue.