From 9d5bac530f464cef9d19eac68a94e67e04a60acb Mon Sep 17 00:00:00 2001 From: Util Date: Sun, 6 Aug 2023 13:17:51 -0500 Subject: Add TWC 228 solutions by Bruce Gray (Raku only). --- challenge-228/bruce-gray/raku/ch-1.raku | 42 +++++++++++++++++++++ challenge-228/bruce-gray/raku/ch-2.raku | 65 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 challenge-228/bruce-gray/raku/ch-1.raku create mode 100644 challenge-228/bruce-gray/raku/ch-2.raku diff --git a/challenge-228/bruce-gray/raku/ch-1.raku b/challenge-228/bruce-gray/raku/ch-1.raku new file mode 100644 index 0000000000..51b9505529 --- /dev/null +++ b/challenge-228/bruce-gray/raku/ch-1.raku @@ -0,0 +1,42 @@ +# Bag, iterated by Pairs: +sub task1a ( @ns --> UInt ) { + return @ns.Bag.map({ .key if .value == 1 }).sum; +} + +# Set difference: +sub task1b ( @ns --> UInt ) { + return ( @ns (-) @ns.repeated ).keys.sum; +} + +# Single-pass: +sub task1c ( @ns --> UInt ) { + my Bool %seen; # tri-state + my UInt $total = 0; + + for @ns -> $n { + my $c = %seen{$n}; + + if $c { next } + elsif $c.defined { $total -= $n; %seen{$n} = True; } + else { $total += $n; %seen{$n} = False; } + } + + return $total; +} + +# Single-pass single-statement / Cosmic Horror with anonymous %seen hash: +sub task1Z ( @ns --> UInt ) { + return sum map { $_ * (1,-1,0)[ %.{$_}++ min 2 ] }, @ns; +} + +constant @tests = map { Hash.new: Z=> .list }, + ( (2, 1, 3, 2), 4 ), + ( (1, 1, 1, 1), 0 ), + ( (2, 1, 3, 4), 10 ), +; +constant @fs = :&task1a, :&task1b, :&task1c, :&task1Z; +use Test; +plan @fs*@tests; +for @fs -> ( :key($f_name), :value(&f) ) { + is f(.), ., "{$f_name} : {.}" for @tests; +} diff --git a/challenge-228/bruce-gray/raku/ch-2.raku b/challenge-228/bruce-gray/raku/ch-2.raku new file mode 100644 index 0000000000..286f9c130b --- /dev/null +++ b/challenge-228/bruce-gray/raku/ch-2.raku @@ -0,0 +1,65 @@ +# Efficient - uses .sort to get all the minimums at once; no re-scanning for .min . +sub task2a ( @ns --> UInt ) { + my @a = @ns; + my @s = @ns.sort; + my $r = 0; + while @a { + while @a[0] != @s[0] { + @a .= rotate; + $r++; + } + $r++; + shift @a; + shift @s; + } + return $r; +} + +# Clearer/denser, but needs inefficient repeated calls to .min. +sub task2b ( @ns ) { + my @a = @ns; + + return sum gather while @a { + my $head = @a.shift; + @a.push: $head if $head > @a.min; + take 1; + } +} + +# Concise evil; inefficent *and* overly subtle. +# Note well the addition of the @ns element count +# to the gathered sum! +sub task2c ( @ns ) { + my @a = @ns; + + return @ns + sum gather while @a { + @a = @a.rotate( take @a.minpairs[0].key ).skip; + } +} + +# Hybrid evil; efficient and dense, +# but uses side-effects and a +# non-intuitive .first instead of a counter. +sub task2d ( @ns ) { + my @a = @ns; + my @s = @ns.sort; + + return first { + my $a_head = @a.shift; + if $a_head > @s.head { @a.push: $a_head } + else { @s.shift } + !@a; + }, 1..Inf; +} + + +constant @tests = map { Hash.new: Z=> .list }, + ( (3, 4, 2), 5 ), + ( (1, 2, 3), 3 ), +; +constant @fs = :&task2a, :&task2b, :&task2c, :&task2d; +use Test; +plan @fs * @tests; +for @fs -> ( :key($f_name), :value(&f) ) { + is f(.), ., "{$f_name} : {.}" for @tests; +} -- cgit