aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2024-07-07 23:59:48 +0100
committerGitHub <noreply@github.com>2024-07-07 23:59:48 +0100
commitaf08a1d8126eb5e5fcce52bf4234980f129b06af (patch)
tree818332129ceb631d01dd98f9c15c3b1aa7f78a65
parent5b36f9398279d4a63d7db3d33c201410ebc49b20 (diff)
parentf1097928aaf3850ff8f70222f973b1874083b85c (diff)
downloadperlweeklychallenge-club-af08a1d8126eb5e5fcce52bf4234980f129b06af.tar.gz
perlweeklychallenge-club-af08a1d8126eb5e5fcce52bf4234980f129b06af.tar.bz2
perlweeklychallenge-club-af08a1d8126eb5e5fcce52bf4234980f129b06af.zip
Merge pull request #10388 from Util/c276
Add TWC 276 solutions by Bruce Gray, in Raku and Perl.
-rw-r--r--challenge-276/bruce-gray/perl/ch-1.pl44
-rw-r--r--challenge-276/bruce-gray/perl/ch-2.pl26
-rw-r--r--challenge-276/bruce-gray/raku/ch-1.raku76
-rw-r--r--challenge-276/bruce-gray/raku/ch-2.raku28
4 files changed, 174 insertions, 0 deletions
diff --git a/challenge-276/bruce-gray/perl/ch-1.pl b/challenge-276/bruce-gray/perl/ch-1.pl
new file mode 100644
index 0000000000..e956858696
--- /dev/null
+++ b/challenge-276/bruce-gray/perl/ch-1.pl
@@ -0,0 +1,44 @@
+use v5.40;
+use ntheory qw<forcomb vecsum>;
+
+sub task1_comb ( $ns_aref ) {
+ my @ns = $ns_aref->@*;
+
+ my $r = 0;
+
+ forcomb {
+ $r++ if vecsum(@ns[@_]) % 24 == 0;
+ } @ns, 2;
+
+ return $r;
+}
+
+
+sub Triangle ($n) { $n * ($n-1) / 2 }
+
+sub task1_hash ( $ns_aref ) {
+ my %bh; # BagHash from Raku
+ $bh{ $_ % 24 }++ for $ns_aref->@*;
+
+ my $r = 0;
+ $r += Triangle( delete $bh{ 0} // 0 );
+ $r += Triangle( delete $bh{12} // 0 );
+
+ $r += $bh{$_} * ($bh{24 - $_} // 0) for grep { $_ < 12 } keys %bh;
+
+ return $r;
+}
+
+
+my @tests = (
+ 2, [12, 12, 30, 24, 24],
+ 3, [72, 48, 24, 5],
+ 0, [12, 18, 24],
+
+ 5998000, [ (12, 12, 30, 24, 24, 5, 6, 18) x 1000 ],
+);
+use Test2::V0 -no_srand => 1; plan @tests / 2 * 2;
+for my ( $expected, $in_array ) (@tests) {
+ is task1_comb($in_array), $expected, "task1_comb : @{$in_array}[0..2]";
+ is task1_hash($in_array), $expected, "task1_hash : @{$in_array}[0..2]";
+}
diff --git a/challenge-276/bruce-gray/perl/ch-2.pl b/challenge-276/bruce-gray/perl/ch-2.pl
new file mode 100644
index 0000000000..e691a60087
--- /dev/null
+++ b/challenge-276/bruce-gray/perl/ch-2.pl
@@ -0,0 +1,26 @@
+use v5.40;
+use List::Util qw<sum0 pairvalues>;
+use Statistics::Frequency;
+
+sub task2 ( $ns_aref ) {
+ my $f = Statistics::Frequency->new( $ns_aref );
+
+ my $max = $f->frequencies_max;
+
+ return sum0 grep { $_ == $max } pairvalues $f->frequencies;
+
+ # Without `Statistics::Frequency` module:
+ # use List::Util qw<max sum0>;
+ # my %bag; $bag{$_}++ for $ns_aref->@*;
+ # my $max_count = max values %bag;
+ # return sum0 grep { $_ == $max_count } values %bag;
+}
+
+my @tests = (
+ 4, [1, 2, 2, 4, 1, 5],
+ 5, [1, 2, 3, 4, 5],
+);
+use Test2::V0 -no_srand => 1; plan @tests/2;
+for my ( $expected, $in_array ) (@tests) {
+ is task2($in_array), $expected;
+}
diff --git a/challenge-276/bruce-gray/raku/ch-1.raku b/challenge-276/bruce-gray/raku/ch-1.raku
new file mode 100644
index 0000000000..3a1a94e4c7
--- /dev/null
+++ b/challenge-276/bruce-gray/raku/ch-1.raku
@@ -0,0 +1,76 @@
+sub times_form_a_complete_day ( @times --> Bool ) { @times.sum %% 24 }
+
+sub task1_combinations ( @ns --> UInt ) {
+ return +grep &times_form_a_complete_day, combinations(@ns, 2);
+}
+
+
+sub dayness ( UInt $hours --> Str ) {
+
+ my $n = $hours % 24;
+
+ return $n == 0 ?? 'FULL_DAY'
+ !! $n == 12 ?? 'HALF_DAY'
+ !! $n < 12 ?? 'LESS_DAY'
+ !! $n > 12 ?? 'MOST_DAY'
+ !! die "Cannot happen"
+ ;
+}
+# When you only need the counts, putting `+` in front of `combinations` makes it a lightning-fast calculation.
+sub task1_classify_X ( @ns --> UInt ) {
+ my ($full, $half, $less, $most) = @ns.classify(&dayness).<FULL_DAY HALF_DAY LESS_DAY MOST_DAY>;
+ my $r = 0;
+
+ $r += +$full.combinations(2);
+ $r += +$half.combinations(2);
+
+ if $less and $most {
+ my @L = ($less »%» 24).Bag.sort;
+ my @M = ($most »%» 24).Bag.sort.reverse;
+
+ # I was planning to walk `while @L and @M {...}`, looking for a linear O(N) way to pair up sums-to-24 and skip over non-pairs, but I could not find it before I realized "just use a hash!", so I finished this sub with `@L X @M` instead, which will always outperform `combinations()`, then wrote `task1_classify_hash_partner` for top performance.
+
+ for @L X @M {
+ $r += [*] .list».value if .list».key.sum == 24;
+ }
+ }
+
+ return $r;
+}
+
+
+sub task1_hash_partner ( @ns --> UInt ) {
+ my BagHash $bh = ( @ns X% 24 ).BagHash;
+
+ my $r = 0;
+ $r += +combinations( $bh{ 0}:delete, 2 );
+ $r += +combinations( $bh{12}:delete, 2 );
+ $r += $bh.map({ .value * $bh{ 24 - .key } if .key < 12 }).sum;
+
+ return $r;
+}
+
+
+constant @tests =
+ ( 2, (12, 12, 30, 24, 24) ),
+ ( 3, (72, 48, 24, 5) ),
+ ( 0, (12, 18, 24) ),
+
+ ( 5998000, ( |(12, 12, 30, 24, 24, 5, 6, 18) xx 1000 ) ),
+;
+my @subs =
+ :&task1_combinations,
+ :&task1_classify_X,
+ :&task1_hash_partner,
+;
+use Test; plan +@tests * +@subs;
+for @subs -> ( :key($sub_name), :value(&task1) ) {
+ for @tests -> ( $expected, @in ) {
+ my $sample = @in <= 9 ?? ~@in !! ~@in.head(9) ~ '...';
+ my $desc = "$sub_name : $sample";
+
+ skip("Too slow: $desc") and next if @in > 200 and $sub_name eq 'task1_combinations';
+
+ is task1(@in), $expected, $desc;
+ }
+}
diff --git a/challenge-276/bruce-gray/raku/ch-2.raku b/challenge-276/bruce-gray/raku/ch-2.raku
new file mode 100644
index 0000000000..256aecc106
--- /dev/null
+++ b/challenge-276/bruce-gray/raku/ch-2.raku
@@ -0,0 +1,28 @@
+constant &task2a = { @^ns.Bag.max(:v).sum } # Only on Rakudo 2023.08 and higher
+
+constant &task2b = { @^ns.Bag.maxpairs».value.sum }
+
+constant &task2c = { .elems * .[0].value given @^ns.Bag.maxpairs }
+
+constant &task2d = { (my %c).push: @^ns.Bag.invert; .key * +.value given %c.max }
+
+constant &task2e = { .key * +.value given @^ns.Bag.classify({.value}, :as{.key}).max }
+
+
+constant @tests =
+ ( 4, (1, 2, 2, 4, 1, 5) ),
+ ( 5, (1, 2, 3, 4, 5) ),
+;
+constant @subs =
+ :&task2a,
+ :&task2b,
+ :&task2c,
+ :&task2d,
+ :&task2e,
+;
+use Test; plan +@tests * +@subs;
+for @subs -> ( :key($sub_name), :value(&task2) ) {
+ for @tests -> ( $expected, @in ) {
+ is task2(@in), $expected, "$sub_name : @in[]";
+ }
+}