diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-07-07 23:59:48 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-07 23:59:48 +0100 |
| commit | af08a1d8126eb5e5fcce52bf4234980f129b06af (patch) | |
| tree | 818332129ceb631d01dd98f9c15c3b1aa7f78a65 | |
| parent | 5b36f9398279d4a63d7db3d33c201410ebc49b20 (diff) | |
| parent | f1097928aaf3850ff8f70222f973b1874083b85c (diff) | |
| download | perlweeklychallenge-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.pl | 44 | ||||
| -rw-r--r-- | challenge-276/bruce-gray/perl/ch-2.pl | 26 | ||||
| -rw-r--r-- | challenge-276/bruce-gray/raku/ch-1.raku | 76 | ||||
| -rw-r--r-- | challenge-276/bruce-gray/raku/ch-2.raku | 28 |
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 ×_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[]"; + } +} |
