From 59c9e9076cc4227df0f34a8e90b0d7b5692f92dd Mon Sep 17 00:00:00 2001 From: Jörg Sommrey <28217714+jo-37@users.noreply.github.com> Date: Tue, 4 May 2021 15:28:16 +0200 Subject: Solution to task 1 --- challenge-111/jo-37/perl/ch-1.pl | 152 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100755 challenge-111/jo-37/perl/ch-1.pl diff --git a/challenge-111/jo-37/perl/ch-1.pl b/challenge-111/jo-37/perl/ch-1.pl new file mode 100755 index 0000000000..4c29382e43 --- /dev/null +++ b/challenge-111/jo-37/perl/ch-1.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl -s +# +use v5.16; +use PDL; +use Test2::V0 '!float'; +use Benchmark 'cmpthese'; +use experimental 'signatures'; + +our ($tests, $examples); + +run_tests() if $tests || $examples; # does not return + +die <[$l / @$m][$l % @$m]; +} + +# Turn the argument into an independent, writable value. +# Enforces call-by-value when applied to a subroutine parameter. +sub v ($v) {$v} + +# Alternative PDL solution. Simple and fast, though not optimal. +sub scan_matrix($pdl, $value) { + any $pdl == $value; +} + + +### Examples and tests + +sub run_tests { + my $m = [ + [ 1, 2, 3, 5, 7 ], + [ 9, 11, 15, 19, 20 ], + [ 23, 24, 25, 29, 31 ], + [ 32, 33, 39, 40, 42 ], + [ 45, 47, 48, 49, 50 ]]; + my $high = @$m**2; + + SKIP: { + skip "examples" unless $examples; + + my $pdl = long $m; + ok !bsearch_matrix($m, v(0), v($high), 35), 'example 1, bsearch'; + ok !scan_matrix($pdl, 35), 'example 1, scan'; + ok bsearch_matrix($m, v(0), v($high), 39), 'example 2, bsearch'; + ok scan_matrix($pdl, 39), 'example 2, scan'; + } + + SKIP: { + skip "tests" unless $tests; + + # Some edge cases. + ok bsearch_matrix($m, v(0), v($high), 1), 'first element'; + ok bsearch_matrix($m, v(0), v($high), 50), 'last element'; + ok !bsearch_matrix($m, v(0), v($high), 0), 'below min'; + ok !bsearch_matrix($m, v(0), v($high), 51), 'above max'; + + # bsearch is taking over: + for (5, 80, 160) { + my $pdl = sequence long, $_, $_; + my $matrix = $pdl->unpdl; + my $high = @$matrix**2; + my $value = $high - 1; + say "\n${_}x${_}:"; + cmpthese(-1, { + scan => sub {scan_matrix($pdl, $value)}, + bsearch => sub { + bsearch_matrix($matrix, v(0), v($high), $value) + } + }); + } + } + + done_testing; + exit; +} + +__DATA__ +5x5: + Rate scan bsearch +scan 115925/s -- -0% +bsearch 115925/s 0% -- + +80x80: + Rate bsearch scan +bsearch 47999/s -- -21% +scan 60703/s 26% -- + +160x160: + Rate scan bsearch +scan 25599/s -- -39% +bsearch 42309/s 65% -- -- cgit From f353639eef4f420b76f87cbac0d2590b89b5fccb Mon Sep 17 00:00:00 2001 From: Jörg Sommrey <28217714+jo-37@users.noreply.github.com> Date: Tue, 4 May 2021 15:48:13 +0200 Subject: Solution to task 2 --- challenge-111/jo-37/perl/ch-2.pl | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 challenge-111/jo-37/perl/ch-2.pl diff --git a/challenge-111/jo-37/perl/ch-2.pl b/challenge-111/jo-37/perl/ch-2.pl new file mode 100755 index 0000000000..c514bdcf27 --- /dev/null +++ b/challenge-111/jo-37/perl/ch-2.pl @@ -0,0 +1,48 @@ +#!/usr/bin/perl -s + +use v5.16; +use warnings; +use experimental 'postderef'; + +# The task states "find the longest English words". This could be meant +# as "all words having the maximum length". My local dictionary has +# only one longest word of this kind, which does not qualify as "longest +# words" - a plural. +# Therefore I'll interpret the term "the longest words" in a way that +# multiple words may be found. +# +# Here $n defines "the longest words". In addition to the word(s) +# having the maximum length, all lengths down to max_len - $n are +# considered as "long", resulting in a larger set of "longest words" if +# $n > 0. +our $n; +$n //= 1; + +die <] dict... + +-n= + Specify the maximum length difference from the maximum length for + words to be printed. Default: 1. Use -n=0 to print the maximum + length word(s) only. + +dict... + dictionary file name(s), e.g. /usr/share/dict/words + +EOS + + +my @word; + +while (<>) { + chomp; + $_ = lc; + # Detect a "self-sorted" word and add it to an array of words having + # the same length. + push $word[length]->@*, $_ if join('', sort split //) eq $_; +} + +# Reverse the order of the collected arrays, pick the first +# $n + 1 thereof, dereference these and print the words. +# @word may contain gaps. +say for map {$_ ? @$_ : ()} (reverse @word)[0 .. $n]; -- cgit