diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2023-12-03 12:55:18 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-03 12:55:18 +0000 |
| commit | 42f3795a1b6f04418786c0837278b58bc910511b (patch) | |
| tree | 01be59866a55822a43c01648b34f455e41454927 | |
| parent | 9b0b58691db7a2821f8d196138d59f57c2b0aee3 (diff) | |
| parent | 8e669183c422cb5361a61c07531f32dcfaf47df2 (diff) | |
| download | perlweeklychallenge-club-42f3795a1b6f04418786c0837278b58bc910511b.tar.gz perlweeklychallenge-club-42f3795a1b6f04418786c0837278b58bc910511b.tar.bz2 perlweeklychallenge-club-42f3795a1b6f04418786c0837278b58bc910511b.zip | |
Merge pull request #9175 from PerlMonk-Athanasius/branch-for-challenge-245
Perl & Raku solutions to Tasks 1 & 2 for Week 245
| -rw-r--r-- | challenge-245/athanasius/perl/ch-1.pl | 197 | ||||
| -rw-r--r-- | challenge-245/athanasius/perl/ch-2.pl | 195 | ||||
| -rw-r--r-- | challenge-245/athanasius/raku/ch-1.raku | 182 | ||||
| -rw-r--r-- | challenge-245/athanasius/raku/ch-2.raku | 190 |
4 files changed, 764 insertions, 0 deletions
diff --git a/challenge-245/athanasius/perl/ch-1.pl b/challenge-245/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..5cad0c9ab4 --- /dev/null +++ b/challenge-245/athanasius/perl/ch-1.pl @@ -0,0 +1,197 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 245 +========================= + +TASK #1 +------- +*Sort Language* + +Submitted by: Mohammad S Anwar + +You are given two array of languages and its popularity. + +Write a script to sort the language based on popularity. + +Example 1 + + Input: @lang = ('perl', 'c', 'python') + @popularity = (2, 1, 3) + Output: ('c', 'perl', 'python') + +Example 2 + + Input: @lang = ('c++', 'haskell', 'java') + @popularity = (1, 3, 2) + Output: ('c++', 'java', 'haskell') + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. Language names are entered as a single, whitespace-separated string named + "lang", for example: --lang="c++ haskell java" +3. Popularity ratings are entered as a list of unsigned integers. The number of + popularity ratings must equal the number of language names. Duplicate popu- + larity ratings are allowed: languages with identical popularities are sorted + in alphabetical order. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Getopt::Long; +use List::MoreUtils qw( mesh ); +use Regexp::Common qw( number ); +use Test::More; + +const my $USAGE => +"Usage: + perl $0 [--lang=<Str>] [<popularity> ...] + perl $0 + + --lang=<Str> A whitespace-separated list of language names + [<popularity> ...] A list of popularity ratings for the given languages +"; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 245, Task #1: Sort Language (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my ($languages, $popularity) = parse_command_line(); + + printf "Input: \@languages = (%s)\n", format_langs( $languages ); + printf " \@popularity = (%s)\n", join ', ', @$popularity; + + my $sorted = sort_languages( $languages, $popularity ); + + printf "Output: (%s)\n", format_langs( $sorted ); + } +} + +#------------------------------------------------------------------------------- +sub sort_languages +#------------------------------------------------------------------------------- +{ + my ($languages, $popularity) = @_; + + my %dict = mesh @$languages, @$popularity; + my @sorted = sort + { # Sort (ascending) by: + $dict{ $a } <=> $dict{ $b } || # 1. popularity; then + $a cmp $b # 2. alphabetical order + + } @$languages; + + return \@sorted; +} + +#------------------------------------------------------------------------------- +sub parse_command_line +#------------------------------------------------------------------------------- +{ + my $lang_str; + + GetOptions( 'lang=s' => \$lang_str ) + or error( 'Error in command line arguments' ); + + defined $lang_str or error( 'No language names given' ); + + my @languages = split / \s+ /x, $lang_str; + my @popularity = @ARGV; + + for (@popularity) + { + / ^ $RE{num}{int} $ /x + or error( qq["$_" is not a valid integer] ); + + $_ >= 0 or error( qq["$_" is negative] ); + } + + scalar @languages == scalar @popularity + or error( 'The input lists have different sizes' ); + + return (\@languages, \@popularity); +} + +#------------------------------------------------------------------------------- +sub format_langs +#------------------------------------------------------------------------------- +{ + my ($languages) = @_; + + return join ', ', map { "'$_'" } @$languages; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $languages_str, $popularity_str, $expected_str) = + split / \| /x, $line; + + for ($test_name, $languages_str, $popularity_str, $expected_str) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @languages = split / \s+ /x, $languages_str; + my @popularity = split / \s+ /x, $popularity_str; + my @expected = split / \s+ /x, $expected_str; + my $sorted = sort_languages( \@languages, \@popularity ); + + is_deeply $sorted, \@expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1|perl c python |2 1 3|c perl python +Example 2|c++ haskell java|1 3 2|c++ java haskell diff --git a/challenge-245/athanasius/perl/ch-2.pl b/challenge-245/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..c94c2be714 --- /dev/null +++ b/challenge-245/athanasius/perl/ch-2.pl @@ -0,0 +1,195 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 245 +========================= + +TASK #2 +------- +*Largest of Three* + +Submitted by: Mohammad S Anwar + +You are given an array of integers >= 0. + +Write a script to return the largest number formed by concatenating some of the +given integers in any order which is also multiple of 3. Return -1 if none +found. + +Example 1 + + Input: @ints = (8, 1, 9) + Output: 981 + + 981 % 3 == 0 + +Example 2 + + Input: @ints = (8, 6, 7, 1, 0) + Output: 8760 + +Example 3 + + Input: @ints = (1) + Output: -1 + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +Assumption +---------- +Duplicates are allowed in the input list. + +Observation +----------- +Any natural number represented in decimal (aka denary) notation is a multiple of +3 if and only if the recursive sum of its digits is also a multiple of 3. + + For example, 819 -> 8 + 1 + 9 = 18 -> 1 + 8 = 9, and 9 is a multiple of 3, + so 819 has been shown to be a multiple of 3. + +From this it follows that, for any given subset of the input integers, concaten- +ating and testing for multiplicity-of-3 will give the same result regardless of +the order in which the integers are concatenated. The solution below takes ad- +vantage of this fact by testing only the largest number which can be formed by +concatenating each possible subset. Since candidate solutions are evaluated in +order from largest to smallest, the first successful candidate is immediately +returned as the best solution. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Algorithm::Combinatorics qw( combinations ); +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $USAGE => +"Usage: + perl $0 [<ints> ...] + perl $0 + + [<ints> ...] A list of integers >= 0\n"; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 245, Task #2: Largest of Three (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my @ints = @ARGV; + + for (@ints) + { + / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] ); + $_ >= 0 or error( qq["$_" is negative] ); + } + + printf "Input: \@ints = (%s)\n", join ', ', @ints; + + my $lot = largest_of_three( \@ints ); + + print "Output: $lot\n"; + } +} + +#------------------------------------------------------------------------------- +sub largest_of_three +#------------------------------------------------------------------------------- +{ + my ($ints) = @_; + + # Note the use of the *stringwise* comparison operator leg instead of <=> + # here: this effectively sorts by digits, most- to least-significant, + # rather than by total numerical value + + my @sorted = sort { $b cmp $a } @$ints; + + for my $digits (reverse (1 .. scalar @sorted)) + { + my $iter = combinations( \@sorted, $digits ); + + while (my $comb = $iter->next) + { + my $candidate = join '', @$comb; + + return $candidate if $candidate % 3 == 0; + } + } + + return -1; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $ints_str, $expected) = split / \| /x, $line; + + for ($test_name, $ints_str, $expected) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @ints = split / \s+ /x, $ints_str; + my $lot = largest_of_three( \@ints ); + + is $lot, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1| 8 1 9 | 981 +Example 2| 8 6 7 1 0| 8760 +Example 3| 1 | -1 +Multiples| 1 1 4 2 | 411 +Small | 8 2 9 | 9 +Tens | 81 9 10 | 981 +Hundreds |198 30 500 |30198 diff --git a/challenge-245/athanasius/raku/ch-1.raku b/challenge-245/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..9668f4efd5 --- /dev/null +++ b/challenge-245/athanasius/raku/ch-1.raku @@ -0,0 +1,182 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 245 +========================= + +TASK #1 +------- +*Sort Language* + +Submitted by: Mohammad S Anwar + +You are given two array of languages and its popularity. + +Write a script to sort the language based on popularity. + +Example 1 + + Input: @lang = ('perl', 'c', 'python') + @popularity = (2, 1, 3) + Output: ('c', 'perl', 'python') + +Example 2 + + Input: @lang = ('c++', 'haskell', 'java') + @popularity = (1, 3, 2) + Output: ('c++', 'java', 'haskell') + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. Language names are entered as a single, whitespace-separated string named + "lang", for example: --lang="c++ haskell java" +3. Popularity ratings are entered as a list of unsigned integers. The number of + popularity ratings must equal the number of language names. Duplicate popu- + larity ratings are allowed: languages with identical popularities are sorted + in alphabetical order. + +=end comment +#=============================================================================== + +use Test; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 245, Task #1: Sort Language (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + #| A whitespace-separated list of language names + + Str :$lang, + + #| A list of popularity ratings for the given languages + + *@popularity where { .elems > 0 && .all ~~ UInt:D } +) +#=============================================================================== +{ + my Str @languages = $lang.split: / \s+ /, :skip-empty; + + @languages.elems == @popularity.elems + or error( 'The input lists have different sizes' ); + + "Input: \@languages = (%s)\n".printf: format-langs( @languages ); + " \@popularity = (%s)\n".printf: @popularity.join: ', '; + + my Str @sorted = sort-languages( @languages, @popularity ); + + "Output: (%s)\n"\.printf: format-langs( @sorted ); +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub sort-languages +( + List:D[Str:D] $languages, + List:D[UInt:D] $popularity where { .elems == $languages.elems } +--> List:D[Str:D] +) +#------------------------------------------------------------------------------- +{ + my UInt %dict{Str} = @$languages Z=> $popularity.map: { .Int }; + my Str @sorted = $languages.sort: + { # Sort (ascending) by: + %dict{ $^a } <=> %dict{ $^b } || # 1. popularity; then + $^a leg $^b # 2. alphabetical order + }; + + return @sorted; +} + +#------------------------------------------------------------------------------- +sub format-langs( List:D[Str:D] $languages --> Str:D ) +#------------------------------------------------------------------------------- +{ + return $languages.map( { "'$_'" } ).join: ', '; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $languages-str, $popularity-str, $expected-str) = + $line.split: / \| /; + + for $test-name, $languages-str, $popularity-str, $expected-str + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Str @languages = $languages-str\.split( / \s+ / ); + my UInt @popularity = $popularity-str.split( / \s+ / ).map: { .Int }; + my Str @expected = $expected-str\ .split( / \s+ / ); + my Str @sorted = sort-languages( @languages, @popularity ); + + is-deeply @sorted, @expected, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + return q:to/END/; + Example 1|perl c python |2 1 3|c perl python + Example 2|c++ haskell java|1 3 2|c++ java haskell + END +} + +################################################################################ diff --git a/challenge-245/athanasius/raku/ch-2.raku b/challenge-245/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..3e27ccbf30 --- /dev/null +++ b/challenge-245/athanasius/raku/ch-2.raku @@ -0,0 +1,190 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 245 +========================= + +TASK #2 +------- +*Largest of Three* + +Submitted by: Mohammad S Anwar + +You are given an array of integers >= 0. + +Write a script to return the largest number formed by concatenating some of the +given integers in any order which is also multiple of 3. Return -1 if none +found. + +Example 1 + + Input: @ints = (8, 1, 9) + Output: 981 + + 981 % 3 == 0 + +Example 2 + + Input: @ints = (8, 6, 7, 1, 0) + Output: 8760 + +Example 3 + + Input: @ints = (1) + Output: -1 + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +Assumption +---------- +Duplicates are allowed in the input list. + +Observation +----------- +Any natural number represented in decimal (aka denary) notation is a multiple of +3 if and only if the recursive sum of its digits is also a multiple of 3. + + For example, 819 -> 8 + 1 + 9 = 18 -> 1 + 8 = 9, and 9 is a multiple of 3, + so 819 has been shown to be a multiple of 3. + +From this it follows that, for any given subset of the input integers, concaten- +ating and testing for multiplicity-of-3 will give the same result regardless of +the order in which the integers are concatenated. The solution below takes ad- +vantage of this fact by testing only the largest number which can be formed by +concatenating each possible subset. Since candidate solutions are evaluated in +order from largest to smallest, the first successful candidate is immediately +returned as the best solution. + +=end comment +#=============================================================================== + +use Test; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 245, Task #2: Largest of Three (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + *@ints where { .elems > 0 && .all ~~ UInt:D } #= A list of integers >= 0 +) +#=============================================================================== +{ + "Input: \@ints = (%s)\n".printf: @ints.join: ', '; + + my Int $lot = largest-of-three( @ints ); + + "Output: $lot".put; +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub largest-of-three( List:D[UInt:D] $ints --> Int:D ) +#------------------------------------------------------------------------------- +{ + # Note the use of the *stringwise* comparison operator leg instead of <=> + # here: this effectively sorts by digits, most- to least-significant, + # rather than by total numerical value + + my UInt @sorted = $ints.sort: { $^b leg $^a }; + + for @sorted.elems ... 1 -> UInt $digits + { + for @sorted.combinations( $digits ) + { + my UInt $candidate = .join( '' ).Int; + + return $candidate if $candidate %% 3; + } + } + + return -1; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $ints-str, $expected) = $line.split: / \| /; + + for $test-name, $ints-str, $expected + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Int @ints = $ints-str.split( / \s+ / ).map: { .Int }; + my Int $lot = largest-of-three( @ints ); + + is $lot, $expected.Int, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + return q:to/END/; + Example 1| 8 1 9 | 981 + Example 2| 8 6 7 1 0| 8760 + Example 3| 1 | -1 + Multiples| 1 1 4 2 | 411 + Small | 8 2 9 | 9 + Tens | 81 9 10 | 981 + Hundreds |198 30 500 |30198 + END +} + +################################################################################ |
