Intersection Sort
with Raku

by Arne Sommer

Intersection Sort with Raku

[331] Published 27. February 2025.

This is my response to The Weekly Challenge #310.

Challenge #310.1: Arrays Intersection

You are given a list of array of integers.

Write a script to return the common elements in all the arrays.

Example 1:
Input: $list = ( [1, 2, 3, 4], [4, 5, 6, 1], [4, 2, 1, 3] )
Output: (1, 4)
Example 2:
Input: $list = ( [1, 0, 2, 3], [2, 4, 5] )
Output: (2)
Example 3:
Input: $list = ( [1, 2, 3], [4, 5], [6] )
Output: ()
File: arrays-intersection
#! /usr/bin/env raku

unit sub MAIN ($arrays-as-string, :v(:$verbose));      # [1]

my @list = $arrays-as-string.split(" ")>>.split(",");  # [2]

say ": List: { @list.raku }" if $verbose;              # [3a]

say "(" ~ ([(&)] @list).keys.sort.join(",") ~ ")";     # [3]

[1] Specify the values with comma as the separator, and the arrays with space as the separtator. See «Running it» below for clarification.

I could have used my normal slurpy array with one string for each array here, and used the space as separator in the strings. But this is more compact, at the cost of reduced legibility.

[2] Split the arrays on a space, and each array individually on a comma.

[3] Use the intersection operator (&) - in combination with the Reduction Metaoperator [] - to get the intersection of all the arrays.

See docs.raku.org/routine/(&),%20infix%20%E2%88%A9 for more information about the intersection operator (&).

See docs.raku.org/language/operators#Reduction_metaoperators for more information about the Reduction Metaoperator [].

The intersection is of the Set persuation, datatype wise that is. So we use the keys method to get the actual values, the keys. Then we sort them, as a Set is unsorted, thus resorting to random order when we extract the content.

See docs.raku.org/type/Set for more information about the Set type.

Note the use of string concatenation (the ~ thingy) on the last row, instead of my preferred code interpolation block as used in [3a]. The next part of the challenge will stick to interpolation...

Running it:

$ ./arrays-intersection "1,2,3,4 4,5,6,1 4,2,1,3"
(1,4)

$ ./arrays-intersection "1,0,2,3 2,4,5"
(2)

$ ./arrays-intersection "1,2,3 4,5 6"
()

Looking good.

With verbose mode:

$ ./arrays-intersection -v "1,2,3,4 4,5,6,1 4,2,1,3"
: List: [("1", "2", "3", "4").Seq, ("4", "5", "6", "1").Seq,
  ("4", "2", "1", "3").Seq]
(1,4)

$ ./arrays-intersection -v "1,0,2,3 2,4,5"
: List: [("1", "0", "2", "3").Seq, ("2", "4", "5").Seq]
(2)

$ ./arrays-intersection -v "1,2,3 4,5 6"
: List: [("1", "2", "3").Seq, ("4", "5").Seq, ("6",).Seq]
()

Challenge #310.2: Sort Odd Even

You are given an array of integers.

Write a script to sort odd index elements in decreasing order and even index elements in increasing order in the given array.

Example 1:
Input: @ints = (4, 1, 2, 3)
Output: (2, 3, 4, 1)

Even index elements: 4, 2 => 2, 4 (increasing order)
Odd index elements : 1, 3 => 3, 1 (decreasing order)
Example 2:
Input: @ints = (3, 1)
Output: (3, 1)
Example 3:
Input: @ints = (5, 3, 2, 1, 4)
Output: (2, 3, 4, 1, 5)

Even index elements: 5, 2, 4 => 2, 4, 5 (increasing order)
Odd index elements : 3, 1 => 3, 1 (decreasing order)
File: sort-odd-even
#! /usr/bin/env raku

unit sub MAIN (*@ints where @ints.elems > 1 && all(@ints) ~~ Int,  # [1]
               :v(:$verbose));

my @even = @ints.shift;                                            # [2]
my @odd  = @ints.shift;                                            # [3]

while @ints.elems                                                  # [4]
{
  @even.push: @ints.shift;                                         # [5]
  @odd.push:  @ints.shift if @ints.elems;                          # [6]
}

say ": Even: @even[]\n: Odd: @odd[]" if $verbose;

say "({ (roundrobin(@even.sort, @odd.sort(-*))).flat.join(", ") })";  # [7]

[1] A slurpy array of 2 or more integers.

[2] Get the first value with an even index (i.e. 0), and place it in this aptly named array.

[3] And the first one with an odd index (i.e. 1).

[4] As long as we have additional values to sort,

[5] • get the next one, having an even index.

[6] • get the next one, if present.

[7] We sort the even indiced array the normal way, and the odd one the other way round (the -* argument to sort). Then we merge the two arrays with roundrobin which gives us one element from each list each time. The result is a two dimentional array, so we flatten it with flat. All of this is wrapped up in some pretty printing code.

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

Running it:

$ ./sort-odd-even 4 1 2 3
(2, 3, 4, 1)

$ ./sort-odd-even 3 1
(3, 1)

$ ./sort-odd-even 5 3 2 1 4
(2, 3, 4, 1, 5)

Looking good.

With verbose mode:

$ ./sort-odd-even -v 4 1 2 3
: Even: 4 2
: Odd: 1 3
(2, 3, 4, 1)

$ ./sort-odd-even -v 3 1
: Even: 3
: Odd: 1
(3, 1)

$ ./sort-odd-even -v 5 3 2 1 4
: Even: 5 2 4
: Odd: 3 1
(2, 3, 4, 1, 5)

And that's it.