by Arne Sommer

# MIS-ing with Raku

[228] Published 18. March 2023.

This is my response to The Weekly Challenge #208.

## Challenge #208.1: Minimum Index Sum

You are given two arrays of strings.

Write a script to find out all common strings in the given two arrays with minimum index sum. If no common strings found returns an empty list.

Example 1: ```Input: @list1 = ("Perl", "Raku", "Love") @list2 = ("Raku", "Perl", "Hate") Output: ("Perl", "Raku") There are two common strings "Perl" and "Raku". Index sum of "Perl": 0 + 1 = 1 Index sum of "Raku": 1 + 0 = 1 ``` Example 2: ```Input: @list1 = ("A", "B", "C") @list2 = ("D", "E", "F") Output: () No common string found, so no result. ``` Example 3: ```Input: @list1 = ("A", "B", "C") @list2 = ("C", "A", "B") Output: ("A") There are three common strings "A", "B" and "C". Index sum of "A": 0 + 1 = 1 Index sum of "B": 1 + 2 = 3 Index sum of "C": 2 + 0 = 2 ```

File: File: minimum-index-sum ```#! /usr/bin/env raku unit sub MAIN (\$list1 = "Perl Raku Love", \$list2 = "Raku Perl Hate", # [1] :v(\$verbose)); my @list1 = \$list1.words; # [2] my @list2 = \$list2.words; # [a2] die "Repetitions in list1" if @list1.elems != @list1.unique.elems; # [3] die "Repetitions in list2" if @list2.elems != @list2.unique.elems; # [3a] my \$mis = Inf; # [4] my @common; # [5] for ^@list1.elems -> \$i # [6] { next unless @list1[\$i] eq any(@list2); # [7] for ^@list2.elems -> \$j # [8] { if @list1[\$i] eq @list2[\$j] # [9] { my \$sum = \$i + \$j; # [10] say ": Index sum of \"@list1[\$i]\": \$i + \$j = \$sum" if \$verbose; next if \$sum > \$mis; # [11] @common = () if \$sum < \$mis; # [12] \$mis = \$sum; # [13] @common.push: @list1[\$i]; # [14] } } } say @common.elems # [15] ?? "(" ~ @common.map({ "\"\$_\"" }).join(", ") ~ ")" # [15a] !! "()"; # [15b] ```

[1] The list of words as two space separated quoted strings, with default values.

[2] Get the words.

[3] The challenge does not tell us how to cope with duplicates in the lists themselves, but I have chosen to make that illegal (as the index for a duplicate word would give more than one answer. I enforce this by removing duplucates, and compare the array lengths.

[4] We are looking for the «minimum index sum», i.e. minimizing this value.

[5] The common strings with the currently «minimum index sum» will end up here.

[6] Iterate over the indices of the words in the first list. The caret (`^`) means «upto, but not including».

[7] Skip the inner loop (over the second list of words), if the `any` junction tells us that we do not have a match (i.e. no common words).

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

[8] Iterate over the indices of the words in the second list.

[9] Are the two words equal?

[10] Compute the index sum.

[11] Disregard this pair (of words, or indices) if the new sum is higher than the «minimum index sum».

[12] Empty the lits of empty strings if the new sum is lower than the old one, as we have found a new value for «minimum index sum».

[13] Update the «minimum index sum». Note that this will also be done if the two variables have the same value.

[14] Add the string (taken from the first list) to the list of common strings.

[15] Do we have a result (common strings). If so, print them with the required formating apllied [15a]. If not, print an ampty set of parens [15b].

Running it:

```\$ ./minimum-index-sum ("Perl", "Raku") \$ ./minimum-index-sum "A B C" "D E F" () \$ ./minimum-index-sum "A B C" "C A B" ("A") ```

Looking good.

With verbose mode:

```\$ ./minimum-index-sum -v : Index sum of "Perl": 0 + 1 = 1 : Index sum of "Raku": 1 + 0 = 1 ("Perl", "Raku") \$ ./minimum-index-sum -v "A B C" "D E F" () \$ ./minimum-index-sum -v "A B C" "C A B" : Index sum of "A": 0 + 1 = 1 : Index sum of "B": 1 + 2 = 3 : Index sum of "C": 2 + 0 = 2 ("A") ```

## Challenge #208.2: Duplicate and Missing

You are given an array of integers in sequence with one missing and one duplicate.

Write a script to find the duplicate and missing integer in the given array. Return -1 if none found.

For the sake of this task, let us assume the array contains no more than one duplicate and missing.

Example 1: ```Input: @nums = (1,2,2,4) Output: (2,3) Duplicate is 2 and Missing is 3. ``` Example 2: ```Input: @nums = (1,2,3,4) Output: -1 No duplicate and missing found. ``` Example 3: ```Input: @nums = (1,2,3,3) Output: (3,4) Duplicate is 3 and Missing is 4. ```

File: duplicate-and-missing ```! /usr/bin/env raku unit sub MAIN (\$nums = "1 2 2 4", :v(\$verbose)); # [1] my @nums = \$nums.words; # [2] die "Not increasing values" unless [<=] @nums; # [3] my \$duplicate = @nums.repeated; # [4] say ": Duplicate: \$duplicate" if \$verbose; my \$current = @nums.shift; # [5] while (@nums.elems) # [6] { if @nums[0] != \$current + 1 # [7] { say ": Missing: { \$current + 1 }" if \$verbose; say "(\$duplicate, { \$current + 1 })"; # [8] exit; # [9] } \$current = @nums.shift; # [10] } say "-1"; # [11] ```

[1] A space separated quoted string (as in the first program) with the values, so that we can have a default value.

[2] Get the words.

[3] Using the Reduction Metaoperator `[]` to enforce that all the values are lower or equal (the `<=` operator) to the next value.

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

[4] The `repeated` methods gives us a list of repeated values, in this case just one element according to the challenge - and thus the duplicate we are looking for.

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

[5] Get the first value.

[6] As long as there are more elements.

[7] The first element in the remaining list should have the value after (+1) the current value. We have found the missing value if it is not.

[8] Print the duplicate value (from [4]) and the missing value.

[9] Exit.

[10] Get ready for the next iteration of the loop (in [6]).

[11] No match (i.e. not reached `exit` above); say so.

Running it:

```\$ ./duplicate-and-missing "1 2 2 4" (2, 3) \$ ./duplicate-and-missing "1 2 3 4" -1 \$ ./duplicate-and-missing "1 2 3 3" (3, 4) ```

Looking good.

With verbose mode, even though it does not really provide any new insights:

```\$ ./duplicate-and-missing -v "1 2 2 4" : Duplicate: 2 : Missing: 3 (2, 3) \$ ./duplicate-and-missing -v "1 2 3 4" : Duplicate: -1 \$ ./duplicate-and-missing -v "1 2 3 3" : Duplicate: 3 : Missing: 4 (3, 4) ```

And that's it.