aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2023-11-19 22:02:11 +0000
committerGitHub <noreply@github.com>2023-11-19 22:02:11 +0000
commit4f90cd459b76172b3a3e6a1664fb9a938875b0dd (patch)
tree8747b22e5bfbd3aaa695a013c2e2c28d84fd9d20
parentb21b72b56d9a29857697d864a69c236fac1ad32d (diff)
parent546103a0c143c6806af3910b229b069eab1e2791 (diff)
downloadperlweeklychallenge-club-4f90cd459b76172b3a3e6a1664fb9a938875b0dd.tar.gz
perlweeklychallenge-club-4f90cd459b76172b3a3e6a1664fb9a938875b0dd.tar.bz2
perlweeklychallenge-club-4f90cd459b76172b3a3e6a1664fb9a938875b0dd.zip
Merge pull request #9095 from Util/c243
Add TWC 243 solutions by Bruce Gray (In Raku, and Javascript).
-rw-r--r--challenge-243/bruce-gray/javascript/ch-1.js145
-rw-r--r--challenge-243/bruce-gray/javascript/ch-2.js54
-rw-r--r--challenge-243/bruce-gray/raku/ch-1.raku16
-rw-r--r--challenge-243/bruce-gray/raku/ch-2.raku32
4 files changed, 247 insertions, 0 deletions
diff --git a/challenge-243/bruce-gray/javascript/ch-1.js b/challenge-243/bruce-gray/javascript/ch-1.js
new file mode 100644
index 0000000000..3d798122d9
--- /dev/null
+++ b/challenge-243/bruce-gray/javascript/ch-1.js
@@ -0,0 +1,145 @@
+#!/usr/bin/env node
+'use strict';
+
+// Procedural, with manual accumulator
+function task1a ( ns ) {
+ let ret = 0;
+
+ for ( const [i, left] of ns.entries() )
+ for ( const right of ns.slice(i+1) )
+ if ( left > (right * 2) )
+ ret++;
+
+ return ret;
+}
+
+// task1a, with inner loop (for&if) refactored to functional (filter&length).
+function task1b ( ns ) {
+ let ret = 0;
+ for ( const [i, left] of ns.entries() ) {
+ ret += ns.slice(i+1).filter((right) => left > (right * 2)).length;
+ }
+ return ret;
+}
+
+// task1b, with the filter expression extracted to a named local function.
+function task1c ( ns ) {
+ let ret = 0;
+ for ( const [i, left] of ns.entries() ) {
+
+ const is_reverse_pair = (right) => left > (right * 2);
+
+ ret += ns.slice(i+1)
+ .filter(is_reverse_pair)
+ .length;
+ }
+ return ret;
+}
+
+// task1c, with the outer loop refactored to .map(), and accumulator embedded in a .reduce().
+function task1d ( ns ) {
+ const add = (a, b) => a + b;
+
+ const count_of_reverse_pairs_with_left = ([i, left]) => {
+
+ const is_reverse_pair = (right) => left > (right * 2);
+
+ return ns.slice(i+1)
+ .filter(is_reverse_pair)
+ .length;
+ }
+
+ return [...ns.entries()].map( count_of_reverse_pairs_with_left ).reduce(add, 0);
+}
+
+// Cannot use a faster .reduce directly on Iterator; experimental feature provided by Node.
+function task1e ( ns ) {
+ const count_of_reverse_pairs_with_this_element = (accumumlator, [i, left]) => {
+ const is_reverse_pair = (right) => left > (right * 2);
+
+ const count = ns.slice(i+1)
+ .filter(is_reverse_pair)
+ .length;
+
+ return accumumlator + count;
+ }
+
+ return [ ...ns.entries() ].reduce(count_of_reverse_pairs_with_this_element, 0);
+}
+
+// task1d with map+reduce merged
+function task1f ( ns ) {
+ // const add = (a, b) => a + b;
+
+ const reverse_pairs = ([i, left]) => {
+
+ const is_reverse_pair = (right) => left > (right * 2);
+
+ return ns.slice(i+1)
+ .filter(is_reverse_pair)
+ .length;
+ }
+ const sum_reverse_pairs = (a, e) => a + reverse_pairs(e);
+
+ return [ ...ns.entries() ].reduce(sum_reverse_pairs, 0);
+}
+
+// pre-doubled once into a parallel `two_n` array, to reduce recalculations.
+function task1g ( ns ) {
+ const two_n = ns.map( n => 2*n );
+
+ const reverse_pairs = ([i, left]) => {
+
+ const is_reverse_pair = (right) => left > right;
+
+ return two_n.slice(i+1)
+ .filter(is_reverse_pair)
+ .length;
+ }
+ const sum_reverse_pairs = (a, e) => a + reverse_pairs(e);
+
+ return [ ...ns.entries() ].reduce(sum_reverse_pairs, 0);
+}
+
+// Extracted "combinations"
+function task1h ( ns ) {
+ const combinations_2 = (arr, func) => {
+ arr.forEach( (left,i) => {
+ arr.slice(i+1).map( (right) => func(left, right) );
+ });
+ }
+
+ let count = 0;
+ const count_wanted = (L,R) => { if ( L > (R * 2) ) count++ };
+ combinations_2(ns, count_wanted);
+ return count;
+}
+
+const subs = [
+ [ 'task1a', task1a ],
+ [ 'task1b', task1b ],
+ [ 'task1c', task1c ],
+ [ 'task1d', task1d ],
+ [ 'task1e', task1e ],
+ [ 'task1f', task1f ],
+ [ 'task1g', task1g ],
+ [ 'task1h', task1h ],
+];
+const tests = [
+ [ 2, [1, 3, 2, 3, 1], 'Example 1 from task' ],
+ [ 3, [2, 4, 3, 5, 1], 'Example 2 from task' ],
+ [ 0, [] , 'Null array' ],
+];
+let test_number = 0;
+function is ( got, expected, desc ) {
+ test_number++;
+ const ok_msg = (got === expected) ? "ok" : "not ok";
+ const description = (typeof desc !== 'undefined') ? ` - ${desc}` : '';
+ console.log(`${ok_msg} ${test_number}${description}`);
+}
+for ( const [ sub_name, task1_coderef ] of subs ) {
+ for ( const [ expected, input, test_name ] of tests ) {
+ const got = task1_coderef(input);
+ is( got, expected, `${sub_name}: ${test_name}`);
+ }
+}
diff --git a/challenge-243/bruce-gray/javascript/ch-2.js b/challenge-243/bruce-gray/javascript/ch-2.js
new file mode 100644
index 0000000000..c5664a5c35
--- /dev/null
+++ b/challenge-243/bruce-gray/javascript/ch-2.js
@@ -0,0 +1,54 @@
+// Procedural
+function task2a ( ns ) {
+ let ret = 0;
+ for ( const x of ns ) {
+ for ( const y of ns ) {
+ ret += Math.floor( x / y );
+ }
+ }
+ return ret;
+}
+
+// Functional, both using extracted code for Cartesian product.
+const cartesian =
+ (...top_level_arrays) => top_level_arrays.reduce(
+ (accum, an_array) => accum.flatMap(
+ (element1) => an_array.map(
+ (element2) => [element1, element2].flat()
+)));
+
+// .map(), then sum via .reduce .
+function task2b (ns) {
+ return cartesian(ns, ns)
+ .map(([x,y]) => Math.floor(x/y))
+ .reduce(((a,b) => a+b),0);
+}
+
+// Do the summing *and* mapping during the .reduce .
+const task2c = (ns) => cartesian(ns, ns).reduce(((a,[x,y]) => a+Math.floor(x/y)),0);
+
+
+
+let test_number = 0;
+function is ( got, expected, desc ) {
+ test_number++;
+ const ok_msg = (got === expected) ? "ok" : "not ok";
+ const description = (typeof desc !== 'undefined') ? ` - ${desc}` : '';
+ console.log(`${ok_msg} ${test_number}${description}`);
+}
+const subs = [
+ [ 'task2a', task2a ],
+ [ 'task2b', task2b ],
+ [ 'task2c', task2c ],
+];
+const tests = [
+ [ 10, [2, 5, 9] , 'Example 1 from task'],
+ [ 49, [7,7,7,7,7,7,7], 'Example 2 from task'],
+ [ 10, [2, 5, 9] , 'Null array'],
+];
+for ( const [ sub_name, task2_coderef ] of subs ) {
+ for ( const [ expected, input, test_name ] of tests ) {
+ const got = task2_coderef(input);
+ is( got, expected, `${sub_name}: ${test_name}`);
+ }
+}
diff --git a/challenge-243/bruce-gray/raku/ch-1.raku b/challenge-243/bruce-gray/raku/ch-1.raku
new file mode 100644
index 0000000000..fee01833c8
--- /dev/null
+++ b/challenge-243/bruce-gray/raku/ch-1.raku
@@ -0,0 +1,16 @@
+sub task1 ( @ns ) {
+ sub is_reverse_pair ( [$left, $right] ) { $left > ($right * 2) }
+
+ return +grep &is_reverse_pair,
+ combinations(@ns, 2);
+}
+
+
+constant @tests =
+ ( 2, (1, 3, 2, 3, 1) ),
+ ( 3, (2, 4, 3, 5, 1) ),
+;
+use Test; plan +@tests;
+for @tests -> ($expected, @ns) {
+ is task1(@ns), $expected;
+}
diff --git a/challenge-243/bruce-gray/raku/ch-2.raku b/challenge-243/bruce-gray/raku/ch-2.raku
new file mode 100644
index 0000000000..b7d2751cab
--- /dev/null
+++ b/challenge-243/bruce-gray/raku/ch-2.raku
@@ -0,0 +1,32 @@
+# Note that `div` can take the place of `floor after division`
+# only because the task specifies integers.
+# https://docs.raku.org/language/operators#infix_div
+# https://docs.raku.org/language/operators#infix_X
+# https://docs.raku.org/language/operators#Cross_metaoperators
+sub task2_simple ( @ns ) {
+ return sum( @ns Xdiv @ns );
+}
+
+constant &task2_inscrutable = { [+] [Xdiv] @^ns xx 2 };
+
+# For 10_000 element array (100 duplicates of a line of 100 random 2-digit numbers):
+# 3 seconds for task2_faster, vs 42 seconds for &task2_simple.
+sub task2_faster ( @ns ) {
+ my @p = @ns.Bag;
+
+ return sum map { [*] |$_».value, |[div] $_».key }, ( @p X @p );
+}
+
+
+
+constant @subs = :&task2_simple, :&task2_inscrutable, :&task2_faster;
+constant @tests =
+ ( 10, (2, 5, 9) ),
+ ( 49, (7, 7, 7, 7, 7, 7, 7) ),
+;
+use Test; plan +@subs * +@tests;
+for @subs -> ( :key($sub_name), :value($task2) ) {
+ for @tests.kv -> $i, ($expected, @ns) {
+ is $task2.(@ns), $expected, "$sub_name.fmt('%-18s'): Example {$i+1}";
+ }
+}