by Arne Sommer

# Sort of Again with Raku

[299] Published 26. July 2024.

This is my response to The Weekly Challenge #279.

## Challenge #279.1: Sort Letters

You are given two arrays, `@letters` and `@weights`.

Write a script to sort the given array `@letters` based on the `@weights`.

Example 1: ```Input: @letters = ('R', 'E', 'P', 'L') @weights = (3, 2, 1, 4) Output: PERL ``` Example 2: ```Input: @letters = ('A', 'U', 'R', 'K') @weights = (2, 4, 1, 3) Output: RAKU ``` Example 3: ```Input: @letters = ('O', 'H', 'Y', 'N', 'P', 'T') @weights = (5, 4, 2, 6, 1, 3) Output: PYTHON ```

File: sort-letters ```#! /usr/bin/env raku unit sub MAIN (\$letters where \$letters.chars > 0, # [1] *@weight where @weight.elems eq \$letters.chars # [2] && all(@weight) ~~ UInt); # [2a] say (\$letters.comb Z @weight) # [3] .sort({ \$^a.[1] <=> \$^b.[1] }) # [4] .map( *.[0] ) # [5] .join; # [6] ```

[1] Ensure at least one letter, all of them in a single string.

[2] A slurpy array of weights, with one weight for each letter, and all of them of the `UInt` (Unsigned Int) type [2a].

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

[3] Combine each letter (as individual letters, courtsey of `comb` on the string) with its weight with the `Z` zip operator. The result is a list containing a sublist for each letter/weight combination.

See docs.raku.org/routine/comb for more information about `comb`.

See docs.raku.org/routine/Z for more information about `Z`.

[4] Sort the list, on the second element (with index 1) of each sublist - the weight.

[5] Then we take the sorted list and pick the first element (with index 0) of each sublist - the letter - with `map`. The result is a sorted list of letters.

[6] Join the list of letters into a single string, and print it (in [3]).

Running it:

```\$ ./sort-letters REPL 3 2 1 4 PERL \$ ./sort-letters AURK 2 4 1 3 RAKU \$ ./sort-letters OHYNPT 5 4 2 6 1 3 PYTHON ```

Looking good.

Note that a weight of zero is perfectly ok, as is gaps:

```\$ ./sort-letters AURK 2 4 0 3 RAKU \$ ./sort-letters AURK 200 400 100 300 RAKU ```

Duplicate weights are sorted in the original order, perhaps surprisingly:

```\$ ./sort-letters AURK 1 1 1 1 AURK ```

The order is the same if you run the program several times, at least on Rakudo v2024.02.

## Challenge #279.2: Split String

You are given a string, `\$str`.

Write a script to split the given string into two containing exactly same number of vowels and return true if you can otherwise false.

Example 1: ```Input: \$str = "perl" Ouput: false ``` Example 2: ```Input: \$str = "book" Ouput: true Two possible strings "bo" and "ok" containing exactly one vowel each. ``` Example 3: ```Input: \$str = "good morning" Ouput: true Two possible strings "good " and "morning" containing two vowels each or "good m" and "orning" containing two vowels each. ```

We do not actually have to split the string at all, just count the vowels. If the number is even, report success, and report failure if it is odd.

File: split-string ```#! /usr/bin/env raku unit sub MAIN (\$str where \$str.chars > 0); # [1] say \$str.comb.grep( * eq any(<a e i o u>) ).elems %% 2; ######## 2 ## # 3 ############################### # 4 ###### ```

[1] Ensure at least one character in the string.

[2] Turn the string into a list of individual characters.

[3] Keep the vowels only, using `grep` on an `any` junction on a list of legal (i.e. english) vowels.

See docs.raku.org/routine/any for more information about `any`.

[4] Count the number of vowels. Are they divisible (the `%%` operator) by 2, thus an even number?

Running it:

```\$ ./split-string perl False \$ ./split-string book True \$ ./split-string "good morning" True ```

Looking good.

But...

```\$ ./split-string bcd True ```

Zero is divisible by 2. And that gives us a false positive.

Let us fix that.

File: split-string-zero ```#! /usr/bin/env raku unit sub MAIN (\$str where \$str.chars > 0); my \$elems = \$str.comb.grep( * eq any() ).elems; say so \$elems && \$elems %% 2; ```

Not quite as elegang as the first version, but the result is correct:

```\$ ./split-string-zero bcd False ```

And that's it.