## 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({ . - . })
.Str;
}
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;
}
``````
• `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. "Util" on IRC and PerlMonks. Frequent speaker on Perl and Raku, but infrequent blogger.