by Arne Sommer

# Nothing But Strings with Raku

[259] Published 21. October 2023.

This is my response to The Weekly Challenge #239.

## Challenge #239.1: Same String

You are given two arrays of strings.

Write a script to find out if the word created by concatenating the array elements is the same.

Example 1: ```Input: @arr1 = ("ab", "c") @arr2 = ("a", "bc") Output: true Using @arr1, word1 => "ab" . "c" => "abc" Using @arr2, word2 => "a" . "bc" => "abc" ``` Example 2: ```Input: @arr1 = ("ab", "c") @arr2 = ("a", "bc") Output: true Using @arr1, word1 => "ab" . "c" => "abc" Using @arr2, word2 => "a" . "bc" => "abc" ``` Example 3: ```Input: @arr1 = ("ab", "c") @arr2 = ("ac", "b") Output: false Using @arr1, word1 => "ab" . "c" => "abc" Using @arr2, word2 => "ac" . "b" => "acb" ```

This is easy, if we assume that the order of the array elements matter - as inferred by the examples.

```#! /usr/bin/env raku unit sub MAIN (\$arr1, \$arr2); # [1] say \$arr1.words.join eq \$arr2.words.join # [2] ?? 'true' # [2a] !! 'false'; # [2b] ```

[1] Two input strings, with space as the separator between the array elements.

[2] Get the array elements (with `words`), glue them together (without the spaces, with `join`) and compare the two resulting strings. Print 'true' if they are equal [2a], and 'false' [2b] if not.

Running it:

```\$ ./same-string "ab c" "a bc" true \$ ./same-string "ab c" "ac b" false \$ ./same-string "ab cd e" "abcde" true ```

It is easyish to support random order:

File: same-string-shuffle ```#! /usr/bin/env raku unit sub MAIN (\$arr1, \$arr2); for \$arr1.words.permutations>>.join.unique -> \$first # [1] { for \$arr2.words.permutations>>.join.unique -> \$second # [2] { if \$first eq \$second # [3] { say 'true'; # [3a] exit; # [3b] } } } say 'false'; # [4] ```

[1] Split the first string into words, generate all the possible permutations (shuffled lists), and join each one into a single string. Remove duplicates (*), if any (with `unique`). Iterate over them.

[2] Ditto, for the second string.

[3] Equal? If so, say so [3a] and exit [3b].

[4] We have looked through all the permutations without finding a match. Then we have failed. Say so.

[*] Duplicates occur if we have duplicate values in the input array. E.g. `"a", "a", "b"`.

Running it gives the expected result:

```\$ ./same-string-shuffle "ab c" "a bc" true \$ ./same-string-shuffle "ab c" "ac b" false \$ ./same-string-shuffle "ab cd e" "abcde" true ```

Let us show off random order:

```\$ ./same-string-shuffle "c e ab d" "abcde" true \$ ./same-string-shuffle "ce ab d" "abcde" false ```

Missing verbose mode?

It is easy to add, but the duplicate removal (`unique` in [1] and [2]) had to go.

File: same-string-verbose ```#! /usr/bin/env raku unit sub MAIN (\$arr1, \$arr2, :v(:\$verbose)); for \$arr1.words.permutations -> @first # [1] { for \$arr2.words.permutations -> @second # [1a] { if @first.join eq @second.join # [1b] { say ": { @first.map({ "\"\$_\"" }).join(" ") } === \ { @second.map({ "\"\$_\"" }).join(" ") }" if \$verbose; say 'true'; exit; } elsif \$verbose { say ": { @first.map({ "\"\$_\"" }).join(" ") } =!= \ { @second.map({ "\"\$_\"" }).join(" ") }"; } } } say 'false'; ```

[1] We have arrays this time in the two loops, so we must join them together (in [1b]) before we can compare the strings.

Running it:

```\$ ./same-string-verbose -v "ab c" "a bc" : "ab" "c" === "a" "bc" true \$ ./same-string-verbose -v "c e ab d" "abcde" : "c" "e" "ab" "d" =!= "abcde" : "c" "e" "d" "ab" =!= "abcde" : "c" "ab" "e" "d" =!= "abcde" : "c" "ab" "d" "e" =!= "abcde" : "c" "d" "e" "ab" =!= "abcde" : "c" "d" "ab" "e" =!= "abcde" : "e" "c" "ab" "d" =!= "abcde" : "e" "c" "d" "ab" =!= "abcde" : "e" "ab" "c" "d" =!= "abcde" : "e" "ab" "d" "c" =!= "abcde" : "e" "d" "c" "ab" =!= "abcde" : "e" "d" "ab" "c" =!= "abcde" : "ab" "c" "e" "d" =!= "abcde" : "ab" "c" "d" "e" === "abcde" true \$ ./same-string-verbose -v "ce ab d" "abcde" : "ce" "ab" "d" =!= "abcde" : "ce" "d" "ab" =!= "abcde" : "ab" "ce" "d" =!= "abcde" : "ab" "d" "ce" =!= "abcde" : "d" "ce" "ab" =!= "abcde" : "d" "ab" "ce" =!= "abcde" false ```

## Challenge #239.2: Consistent Strings

You are given an array of strings and allowed string having distinct characters.

You are given an array of strings and allowed string having distinct characters.

Write a script to return the number of consistent strings in the given array.

Example 1: ```Input: @str = ("ad", "bd", "aaab", "baa", "badab") \$allowed = "ab" Output: 2 Strings "aaab" and "baa" are consistent since they only contain characters 'a' and 'b'. ``` Example 2: ```Input: @str = ("a", "b", "c", "ab", "ac", "bc", "abc") \$allowed = "abc" Output: 7 ``` Example 3: ```Input: @str = ("cc", "acd", "b", "ba", "bac", "bad", "ac", "d") \$allowed = "cad" Output: 4 Strings "cc", "acd", "ac", and "d" are consistent.```
File: consistent-string ```#! /usr/bin/env raku unit sub MAIN (\$allowed, *@str where @str.elems > 0); # [1] my @allow-canonical = \$allowed.comb; # [2] my \$consistent = 0; # [3] for @str -> \$str # [4] { \$consistent++ if \$str.comb.unique (<=) @allow-canonical; # [5] } say \$consistent; # [6] ```

[1] The allowed characters as the first argument, followed by the strings.

[2] A list of allowed characters.

[3] The final count will end up here.

[4] Iterate over the strings.

[5] Increse the counter if the characters in the string is a subset (or equal) (the `(<=)` operator) to the allowed characters.

See docs.raku.org/language/operators infix (<=) for more information about the subset or equal to operator `(<=)`.

[6] Print the result.

Running it:

```\$ ./consistent-string ab ad bd aaab baa badab 2 \$ ./consistent-string abc a b c ab ac bc abc 7 \$ ./consistent-string cad cc acd b ba bac bad ac d 4 ```

Looking good.

Missing verbose mode? Let us remedy that.

File: consistent-string-verbose ```#! /usr/bin/env raku unit sub MAIN (\$allowed, *@str where @str.elems > 0, :v(:\$verbose)); my @allow-canonical = \$allowed.comb; my \$consistent = 0; for @str -> \$str { my @str-canonical = \$str.comb.unique; if @str-canonical (<=) @allow-canonical { \$consistent++; say ": + \$str - consistent" if \$verbose; } elsif \$verbose { say ": - \$str" if \$verbose; } } say \$consistent; ```

Running it:

```\$ ./consistent-string-verbose -v ab ad bd aaab baa badab : - ad : - bd : + aaab - consistent : + baa - consistent : - badab 2 \$ ./consistent-string-verbose -v abc a b c ab ac bc abc : + a - consistent : + b - consistent : + c - consistent : + ab - consistent : + ac - consistent : + bc - consistent : + abc - consistent 7 \$ ./consistent-string-verbose -v cad cc acd b ba bac bad ac d : + cc - consistent : + acd - consistent : - b : - ba : - bac : - bad : + ac - consistent : + d - consistent 4 ```

And that's it.