## TWC 193: Evens and Oddballs

In which we revisit seventh grade, and sing in the key of "A".

# TWC Task #1 - Binary String

## Task

Calculate all possible binary numbers of size $n.

## Observations

In 7th grade, I noticed that you can construct all the binary numbers by starting with 0 and 1, then prepending 0-and-1 to all the prior numbers, doubling the size of the calculated each time:

```
0
1
00
01
10
11
000
001
010
011
100
101
110
111
```

I used this method in the Perl solution.

Loosely related: This week, my 5-year-old granddaughter

showed us how she can count to `2_000_000`

:

Cora Kate: "*one* million, *two* million !!!"

## Raku

I could have written:

```
sub task1 ( UInt $n ) { ^(2**$n) .fmt("\%0{$n}b") }
```

, but that gives the wrong answer when `$n`

is `0`

. So instead:

```
multi sub task1 ( 1 ) { <0 1> }
multi sub task1 ( UInt $n ) { [X~] (<0 1> xx $n) }
```

The `multi`

is needed because the `X`

cross-operator will operate on a solo `<0 1>`

by unpacking it, translating to `'0' ~ '1'`

, which is not what we want.

## Perl

I could have written:

```
sub task1 ( $n ) { map { sprintf "%0${n}b", $_ } 0 .. (2**$n)-1 }
```

, but that gives the wrong answer when `$n`

is `0`

. (Sounds familiar.) So instead:

```
sub task1 ($n) {
my @r = ("");
@r = ( map("0$_", @r),
map("1$_", @r) ) for 1..$n;
return @r;
}
```

# TWC Task #2 - Odd String

## Task

All string elements of a given list will have the same "distance between adjacent characters", except one. Return that one string element.

## Observations

This task is naturally broken into:

- Calculating the distance
- Grouping based on that distance
- Selecting the group with only one element

The solution will probably be clearer if we keep those aspects separate.

Changing `"be"`

into `1,4`

to get the difference of `3`

can be replaced with `ord`

, since the base values don't matter, only their relative distances.

## Raku

I could have golfed this to:

```
@L.classify(~*.comb.rotor(2=>-1).map({[-] $_».ord})).values.min(+*)
```

, but T'is the season of thankfulness and giving. Also, I am not happy with the assumptions that the task is making, so I structured it to better allow for warnings.

```
sub oddballs ( @list, &matcher ) {
my %h = @list
.classify(&matcher)
.values
.classify({ .elems == 1 ?? 'Oddball' !! 'Clique' });
warn "Multiple cliques exist" if %h<Clique>.elems > 1;
return %h<Oddball>.list;
}
sub neighbor_distances ( Str $s --> Str ) {
return $s.comb
.map(&ord)
.rotor(2 => -1)
.map({ .[1] - .[0] })
.Str;
}
sub task2 (@list) {
die "Must have at least 3 to have an oddball" if @list.elems < 3;
my @o = oddballs( @list, &neighbor_distances );
warn "No oddballs found" if not @o;
warn "More than one oddball" if @o.elems > 1;
return @o.head;
}
```

I want to point out that the "neighbor-difference after numeric translation" is a fine way to specify the desired grouping, but an alternative could also serve:

```
$s .= trans( ['b'..'z'] => ['a'..'y'] ) until $s.contains: 'a';
```

Reducing each letter along the alphabet until any of them is an `a`

would produce the same results.

## Perl

Using many modules, to better parallel the Raku solution:

```
use v5.36;
use List::Util qw<mesh pairvalues>;
use List::MoreUtils qw<slide>;
use List::Categorize qw<categorize>;
sub diffs ( $s ) {
state %A_N = mesh ['a'..'z'], [0..25];
return join ':',
slide { $b - $a }
@A_N{ split '', $s };
}
sub oddballs ( @s ) {
return grep { @{$_} == 1 }
pairvalues
categorize { diffs($_) } @s;
}
sub task2 ( @s ) {
my @r = oddballs(@s);
warn if @r != 1;
return $r[0][0];
}
```

`mesh`

is Raku's`Z`

.`slide`

is Raku's`.rotor(2 => -1)`

.`categorize`

is Raku's`.classify`

.`pairvalues`

makes up for Raku's Pairs being true objects.

I used the `@`

-sigil on a hash to access Perl's "hash slicing", allowing *all* of the letters to be translated in one go.

## Leave a comment