diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-04-29 00:13:20 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-29 00:13:20 +0100 |
| commit | a22ea6213e4a89213f4ccd1d40ab34d989d2fe78 (patch) | |
| tree | 171d9a7f81cbdda29fcf1f1723a0294028749d9d | |
| parent | c7f7a2a52657cb1dc6aa7be06320b61238ce7c6b (diff) | |
| parent | 71eba32c638f5ebd9a8b077bad5bcda82c07e238 (diff) | |
| download | perlweeklychallenge-club-a22ea6213e4a89213f4ccd1d40ab34d989d2fe78.tar.gz perlweeklychallenge-club-a22ea6213e4a89213f4ccd1d40ab34d989d2fe78.tar.bz2 perlweeklychallenge-club-a22ea6213e4a89213f4ccd1d40ab34d989d2fe78.zip | |
Merge pull request #10006 from Util/c266
Add TWC 266 solutions by Bruce Gray, in Raku only.
| -rw-r--r-- | challenge-266/bruce-gray/raku/ch-1.raku | 50 | ||||
| -rw-r--r-- | challenge-266/bruce-gray/raku/ch-2.raku | 88 |
2 files changed, 138 insertions, 0 deletions
diff --git a/challenge-266/bruce-gray/raku/ch-1.raku b/challenge-266/bruce-gray/raku/ch-1.raku new file mode 100644 index 0000000000..f655e6fc5b --- /dev/null +++ b/challenge-266/bruce-gray/raku/ch-1.raku @@ -0,0 +1,50 @@ +# Just as easy to solve this task for any number of lines, instead of just two. + +# Common code for "list elements occuring only once". +constant &non-dups = *.Bag.grep( *.value == 1 )».key; + +# Solves the problem along the lines of the actual description of the task. +sub task1_reduce ( @lines ) { + return @lines.map( *.words.&non-dups ).reduce(&[⊎]).&non-dups || ''; +} + +# Re-thinking the task, +# it becomes clear that the distinction between lines in irrelevant; +# what is wanted are the words that only occur once in any line. +# Restated: +# A word is uncommon +# if it appears exactly once in one of the sentences +# and doesn’t appear in other sentence. +# is logically mappable to: +# A word is uncommon +# if it appears exactly once +# across all of the sentences. +sub task1_rethought ( @lines ) { + return @lines».words.flat.&non-dups || ''; +} + +sub task1_set_subtraction ( @lines ) { + # return keys( .list ∖ .repeated ) || '' given @lines».words.flat.cache; # One-liner; needlessly obtuse. + + my @w = @lines».words.flat; + + return ( @w (-) @w.repeated ).keys || ''; +} + + +constant @tests = + ( 'Mango is sweet' , 'Mango is sour' , ( 'sweet', 'sour' ) ), + ( 'Mango Mango' , 'Orange' , ( 'Orange', ) ), + ( 'Mango is Mango' , 'Orange is Orange' , ( '', ) ), +; +constant @subs = + :&task1_reduce, + :&task1_rethought, + :&task1_set_subtraction, +; +use Test; plan +@tests * +@subs; +for @subs -> ( :key($sub_name), :value(&task1) ) { + for @tests -> ( $line1, $line2, @expected ) { + is-deeply task1(($line1, $line2)).sort, @expected.sort, "$sub_name : $line1"; + } +} diff --git a/challenge-266/bruce-gray/raku/ch-2.raku b/challenge-266/bruce-gray/raku/ch-2.raku new file mode 100644 index 0000000000..a4739b0afd --- /dev/null +++ b/challenge-266/bruce-gray/raku/ch-2.raku @@ -0,0 +1,88 @@ +# Walk the matrix once, noting by coordinate whether the cell +# is on either of the diagonals. +# Early return on first cell containing the wrong (zero/non-zero) value. +sub task2_efficient ( @mat --> Bool ) { + die "Ill-defined for matrix of size zero" unless @mat.elems; + die "Not square" unless @mat.elems == @mat».elems.all; + + for @mat.kv -> $i, @row { + for @row.kv -> $j, $cell { + + my \is_zero = $cell == 0; + + my \is_diag = $i-$j == 0 + || $i+$j == @row.end; + + return False if is_diag and is_zero + or !is_diag and !is_zero; + } + } + + return True; +} + +# Pre-calculate all the coordinates of diagonal and anti-diagonal cells. +# The `unique` removes the doubled coordinate that occurs in the very center of odd-sized matrixes. +# The `sort` is critical when the use of these coordinates is to modify any row in the bottom half of the matrix. +sub diagonals_i_j ( $size ) { + return (^$size).map({ |(($_, $_), ($_, $size - 1 - $_)) }) + .unique( :with(&[eqv]) ) + .sort; +} + +# Find all (i,j) coordinates that are non-zero, and check that they exactly match the diagonals. +sub task2_concise ( @m --> Bool ) { + return diagonals_i_j(+@m) eqv sort grep ->(\i,\j) { @m[i][j] !== 0 }, [X] @m.keys xx 2; +} + +# Clone the matrix, extract the diagonal and anti-diagonal cells from each row and store in a seperate array, then check that all diags are non-zero and the remaining matrix cells are all zero. +sub task2_copy ( @matrix --> Bool ) { + die "Ill-defined for matrix of size zero" unless @matrix.elems; + die "Not square" unless @matrix.elems == @matrix».elems.all; + + my @m = @matrix.map({[ .list ]}); # Mutable copy + + # Using gather/take instead of `map` for clarity; @m is mutated in the loop. + my @diag_values = gather for diagonals_i_j(+@m).reverse -> (\i,\j) { + take @m[i].splice(j, 1).head; + } + + return ?( @diag_values.none == 0 + and @m»<>.flat.all == 0 ); +} +# There are several hybrids of task2_copy that I did not code here: +# * Early return during the `gather for` loop. +# * Setting `@m[i][j]` to `0` after `take`, instead of `.splice`-ing it out. +# Using `0` would also remove the `.sort` in diagonals_i_j(), and `.reverse` in its call. + + +constant @tests = + ( 'Task example 1', True, ( + (1, 0, 0, 2), + (0, 3, 4, 0), + (0, 5, 6, 0), + (7, 0, 0, 1), + )), + ( 'Task example 2', False, ( + (1, 2, 3), + (4, 5, 6), + (7, 8, 9), + )), + ( 'Task example 3', True, ( + (1, 0, 2), + (0, 3, 0), + (4, 0, 5), + )), + +; +constant @subs = + :&task2_efficient, + :&task2_concise, + :&task2_copy, +; +use Test; plan +@tests * +@subs; +for @subs -> ( :key($sub_name), :value(&task2) ) { + for @tests -> ( $test_name, $expected, @matrix ) { + is task2(@matrix), $expected, "$sub_name : $test_name"; + } +} |
