List the List
with Raku

by Arne Sommer

List the List with Raku

[397] Published 14. May 2026.

This is my response to The Weekly Challenge #373.

#373.1 Equal List You are given two arrays of strings.

Write a script to return true if the two given array represent the same strings otherwise false.

Example 1:
Input: @arr1 = ("a", "bc")
       @arr2 = ("ab", "c")
Output: true

Array 1: "a" + "bc" = "abc"
Array 2: "ab" + "c" = "abc"
Example 2:
Input: @arr1 = ("a", "b", "c")
       @arr2 = ("a", "bc")
Output: true

Array 1: "a" + "b" + "c" = "abc"
Array 2: "a" + "bc" = "abc"
Example 3:
Input: @arr1 = ("a", "bc")
       @arr2 = ("a", "c", "b")
Output: false

Array 1: "a" + "bc" = "abc"
Array 2: "a" + "c" + "b" = "acb"
Example 4:
Input: @arr1 = ("ab", "c", "")
       @arr2 = ("", "a", "bc")
Output: true

Array 1: "ab" + "c" + "" = "abc"
Array 2: ""  + "a" + "bc" = "abc"
Example 5:
Input: @arr1 = ("p", "e", "r", "l")
       @arr2 = ("perl")
Output: true

Array 1: "p" + "e" + "r" + "l" = "perl"
Array 2: "perl"

File: equal-list
#! /usr/bin/env raku

unit sub MAIN (*@arrays where @arrays.elems > 2,
               :s(:$separator) = '|';
               :v(:$verbose));

my $sep-at = @arrays.first($separator, :k)
  || die "Did not find array separator";

my @arr1 = @arrays[0 .. $sep-at -1];
my @arr2 = @arrays[$sep-at +1 .. *];

my $arr1 = @arr1.join;
my $arr2 = @arr2.join;

if $verbose
{
  say ":\@arr1: { @arr1.map({ '"' ~ $_ ~ '"' }).join(", ") } \
    -> \"$arr1\"";
  say ":\@arr2: { @arr2.map({ '"' ~ $_ ~ '"' }).join(", ") } \
    -> \"$arr2\"";
}

say $arr1 eq $arr2;

[3] We cannot specify two slurpy arrays, so one will have to do.

[4] Then we specify a dividing string, to be used to separate the two parts. Note the default value.

[7] Get the index of the first instance of the separator string in the array. The k part tells first to give the key - i.e. the index - instead of the value itself.

See docs.raku.org/routine/first for more information about first.

There may be additional instances of the separator string, but the split will be done on the first one (from the left). So any duplicates will end up in the second array. It is highly advisable to avoid using a separator string that occurs natively in the arrays.

[10] Extract the first array, with an array slice; everything before the separator.

[11] And the second array; everything after the separator.

[13] Join the elements in the first array to a string.

[14] Do the same with the second one.

[24] Are they equal?

Running it:

$ ./equal-list "a" "bc" "|" "ab" "c"
True

$ ./equal-list "a" "b" "c" "|" "a" "bc"
True

$ ./equal-list "a" "bc" "|" "a" "b" "c" 
True

$ ./equal-list "ab" "c" "" "|" "" "a" "bc" 
True

$ ./equal-list p e r l "|" perl
True

Looking good.

With verbose mode:

$ ./equal-list -v "a" "bc" "|" "ab" "c"
:@arr1: "a", "bc" -> "abc"
:@arr2: "ab", "c" -> "abc"
True

$ ./equal-list -v "a" "b" "c" "|" "a" "bc"
:@arr1: "a", "b", "c" -> "abc"
:@arr2: "a", "bc" -> "abc"
True

$ ./equal-list -v "a" "bc" "|" "a" "b" "c" 
:@arr1: "a", "bc" -> "abc"
:@arr2: "a", "b", "c" -> "abc"
True

$ ./equal-list -v "ab" "c" "" "|" "" "a" "bc" 
:@arr1: "ab", "c", "" -> "abc"
:@arr2: "", "a", "bc" -> "abc"
True

$ ./equal-list -v p e r l "|" perl
:@arr1: "p", "e", "r", "l" -> "perl"
:@arr2: "perl" -> "perl"
True

#373.2 List Division 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.

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

5 / 2 = 2 remainder 1.
The extra element goes into the first chunk.
Example 2:
Input: @list = (1,2,3,4,5,6), $n = 3
Output: ((1,2), (3,4), (5,6))

6 / 3 = 2 remainder 0.
Example 3:
Input: @list = (1,2,3), $n = 2
Output: ((1,2), (3))
Example 4:
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))
Example 5:
Input: @list = (1,2,3), $n = 4
Output: -1
Example 6:
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))
File: list-division
#! /usr/bin/env raku

unit sub MAIN (*@list is copy where @list.elems > 1,
               :$n,
               :v(:$verbose));

if $n > @list.elems
{
  say -1;
  exit;
}

my $bucket-size = @list.elems div $n;
my $extra       = @list.elems % $n;

if $verbose
{
  say ":Bucket size: $bucket-size";
  say ":Extra values: $extra";
}

my @output = gather
{
  while @list.elems
  {
    my $count = $bucket-size;
    if $extra { $count++; $extra--; }
    take @list.splice(0, $count);
  }
}

say "(" ~ @output.map({"(" ~ $_.join(",") ~ ")"}).join(", ")
  ~ ")";

[3] Note the is copy adverb, so that we can change the value later (in [28]). Ensure at lest two elements.

See docs.raku.org/type/Parameter#method_copy for more information about is copy.

[4] Specify the $n value as a named argument.

[7] Report failure (-1) in [9] and exit in [10] if $n is too large.

[13] Get the bucket size; the minimum number of elements in each division (or bucket).

[14] The number of extra elements left over after calculating the bucket size [13].

[22] The gathering (so to speak) of the values in the buckets is a good match for gather/take. We collect the substrings in this array.

See my Raku Gather, I Take article or docs.raku.org/language/control#gather/take for more information about gather/take.

[24] As long as we have more elements to bucketise.

[26] The number of elemets to put in the current bucket.

[27] Add one, if we have any leftovers from [14]. And adjust the leftover count as we use them.

[28] Use splice to extract the required number of elements from the array, and return them with take.

See docs.raku.org/routine/splice for more information about splice.

[32] Pretty print the result, a list of list.

Running it:

$ ./list-division -n=2 1 2 3 4 5
((1,2,3), (4,5))

$ ./list-division -n=3 1 2 3 4 5 6
((1,2), (3,4), (5,6))

$ ./list-division -n=2 1 2 3
((1,2), (3))

$ ./list-division -n=5 1 2 3 4 5 6 7 8 9 10
((1,2), (3,4), (5,6), (7,8), (9,10))

$ ./list-division -n=4 1 2 3
-1

$ ./list-division -n=7 72 57 89 55 36 84 10 95 99 35
((72,57), (89,55), (36,84), (10), (95), (99), (35))

Looking good.

With verbose mode:

$ ./list-division -v -n=2 1 2 3 4 5
:Bucket size: 2
:Extra values: 1
((1,2,3), (4,5))

$ ./list-division -v -n=3 1 2 3 4 5 6
:Bucket size: 2
:Extra values: 0
((1,2), (3,4), (5,6))

$ ./list-division -v -n=2 1 2 3
:Bucket size: 1
:Extra values: 1
((1,2), (3))

$ ./list-division -v -n=5 1 2 3 4 5 6 7 8 9 10
:Bucket size: 2
:Extra values: 0
((1,2), (3,4), (5,6), (7,8), (9,10))

$ ./list-division -v -n=4 1 2 3
-1

$ ./list-division -v -n=7 72 57 89 55 36 84 10 95 99 35
:Bucket size: 1
:Extra values: 3
((72,57), (89,55), (36,84), (10), (95), (99), (35))

And that's it.