## TWC 193: Evens and Oddballs

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

# TWC Task #1 - Binary String

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

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;

}
``````

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.