by Arne Sommer

# An Abundance of Strings with Raku

 Published 4. December 2022.

This is my response to The Weekly Challenge #193.

## Challenge #193.1: Binary String

You are given an integer, `\$n > 0`.

Write a script to find all possible binary numbers of size `\$n`.

Example 1: ```Input: \$n = 2 Output: 00, 11, 01, 10 ``` Example 2: ```Input: \$n = 3 Output: 000, 001, 010, 100, 111, 110, 101, 011 ```

File: binary-string-loop ```#! /usr/bin/env raku unit sub MAIN (Int \$n where \$n > 0); my \$decimal = 0; #  my @binary; #  loop #  { my \$binary = \$decimal.fmt('%0' ~ \$n ~ 'b'); #  last if \$binary.chars > \$n; #  @binary.push: \$binary; #  \$decimal++; #  } say @binary.join(", "); #  ```

 The loop variable (in decimal), from zero up to the limit.

 The binary numbers will end up here, as strings.

 An eternal loop. Note the exit clause in .

 Convert the loop value to binary (with `fmt`), as a zero padded string giving the total length as `\$n`).

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

 exit the loop if we aquired too many digits in the binary representation.

 The next decimal value.

 Print the list nicely.

Running it:

```\$ ./binary-string-loop 2 00, 01, 10, 11 \$ ./binary-string-loop 3 000, 001, 010, 011, 100, 101, 110, 111 ```

I have chosen to print the values sorted by value (increasing). The challenge printed them in a rather random order (e.g. the highest value).

It is certainly possible to make the program shorter. Here it is as a one liner, if you ignore the crash-bang and unit lines:

File: binary-string-map ```#! /usr/bin/env raku unit sub MAIN (Int \$n where \$n > 0); say (0 .. (1 x \$n).parse-base(2)).map( *.fmt('%0' ~ \$n ~ 'b') ).join(", "); ### # 1 ########################## # 2 ######################### # 3 ####### ```

 Start with all the decimal values (from "0" to e.g. "8" (binary "1111") if \$n == 4, using the string repetition operator `x` and `parse-base`).

See docs.raku.org/routine/x for more information about the string repetition operator `x`.

See docs.raku.org/routine/parse-base for more information about `parse-base`.

 Convert to binary, zero padded.

 Join the values, and let the `say` up front print the lot.

Running it gives the same result as first version:

```\$ ./binary-string-map 2 00, 01, 10, 11 \$ ./binary-string-map 3 000, 001, 010, 011, 100, 101, 110, 111 ```

## Challenge #193.2: Odd String

You are given a list of strings of same length, `@s`.

Write a script to find the odd string in the given list. Use positional value of alphabet starting with `0`, i.e. `a = 0, b = 1, ... z = 25`.

Find the difference array for each string as shown in the example. Then pick the odd one out.

Example 1: ```Input: @s = ("adc", "wzy", "abc") Output: "abc" Difference array for "adc" => [ d - a, c - d ] => [ 3 - 0, 2 - 3 ] => [ 3, -1 ] Difference array for "wzy" => [ z - w, y - z ] => [ 25 - 22, 24 - 25 ] => [ 3, -1 ] Difference array for "abc" => [ b - a, c - b ] => [ 1 - 0, 2 - 1 ] => [ 1, 1 ] The difference array for "abc" is the odd one. ``` Example 2: ```Input: @s = ("aaa", "bob", "ccc", "ddd") Output: "bob" Difference array for "aaa" => [ a - a, a - a ] => [ 0 - 0, 0 - 0 ] => [ 0, 0 ] Difference array for "bob" => [ o - b, b - o ] => [ 14 - 1, 1 - 14 ] => [ 13, -13 ] Difference array for "ccc" => [ c - c, c - c ] => [ 2 - 2, 2 - 2 ] => [ 0, 0 ] Difference array for "ddd" => [ d - d, d - d ] => [ 3 - 3, 3 - 3 ] => [ 0, 0 ] The difference array for "bob" is the odd one. ```

File: odd-string ```#! /usr/bin/env raku unit sub MAIN (*@s where ( [==] @s>>.chars), :v(:\$verbose)); #  my %diff; #  for @s -> \$string #  { my @letters = \$string.comb; #  my @diff; #  my \$first; #  my \$second = @letters.shift; #  while (@letters.elems) { #  my \$first = \$second; #  \$second = @letters.shift; #  my \$diff = \$second.ord - \$first.ord; #  @diff.push: \$diff; #  } %diff{ @diff.join: " " }.push: \$string; #  say ": \$string -> @diff[]" if \$verbose; } say ":" ~ %diff.raku if \$verbose; say %diff.grep({ \$_.value.elems == 1 }).map( *.value ).Str; #  ```

 Ensure that all the string lengths (` @s>>.chars`) are identical (`[==]`). Note the missing check on legal letters only. (The challenge does not actually say that we are limited to lower case letters, though it implies it.)

 The difference array for each string will end up here.

 Iterate over each string.

 Get the individual letters.

 The difference values for the current string will end up here.

 The first value will be kept here,

 and the second one here. The initial state is messy, but will be corrected inside the loop.

 As long as we have more letters,

 Move the second one (from the previous iteration) up front, as the new first.

 Get a new second.

 Get the difference, using the unicode codepoints (from `ord`).

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

 Add that difference to the list.

 The difference string is the difference values added together (space separated). Note the use of `push` to add the value to a list - which we store in the hash.

 Print the string(s) that have a unique difference string (i.e. occur just once, courtesy of the `grep`). The `map` gives us the value, and not the hash pair (key, value)

Running it:

```\$ ./odd-string adc wzy abc abc \$ ./odd-string aaa bob ccc ddd bob \$ ./odd-string adc wzy abc 111 abc 111 ```

With verbose mode:

```\$ ./odd-string -v aaa bob ccc ddd : aaa -> 0 0 : bob -> 13 -13 : ccc -> 0 0 : ddd -> 0 0 :{"0 0" => \$["aaa", "ccc", "ddd"], "13 -13" => \$["bob"]} bob \$ ./odd-string -v adc wzy abc 111 : adc -> 3 -1 : wzy -> 3 -1 : abc -> 1 1 : 111 -> 0 0 :{"0 0" => \$[IntStr.new(111, "111")], "1 1" => \$["abc"], "3 -1" => \$["adc", "wzy"]} abc 111 \$ ./odd-string -v adc wzy abc 111 222 : adc -> 3 -1 : wzy -> 3 -1 : abc -> 1 1 : 111 -> 0 0 : 222 -> 0 0 :{"0 0" => \$[IntStr.new(111, "111"), IntStr.new(222, "222")], "1 1" => \$["abc"], "3 -1" => \$["adc", "wzy"]} abc ```

#### The odd one out...

The two examples leave no room for confusion, but what if we do not have one string with an unique difference string? As in my `adc wzy abc 111`?

Or even worse, if we have something like these:

```\$ ./odd-string -v adc wzy abc def : adc -> 3 -1 : wzy -> 3 -1 : abc -> 1 1 : def -> 1 1 :{"1 1" => \$["abc", "def"], "3 -1" => \$["adc", "wzy"]} \$ ./odd-string -v adc wzy abc def ghi : adc -> 3 -1 : wzy -> 3 -1 : abc -> 1 1 : def -> 1 1 : ghi -> 1 1 :{"1 1" => \$["abc", "def", "ghi"], "3 -1" => \$["adc", "wzy"]} ```

My program does not handle these examples, as it is hard to decide what to do in these cases.

And that's it.