diff options
| author | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2024-07-07 17:45:58 +1000 |
|---|---|---|
| committer | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2024-07-07 17:45:58 +1000 |
| commit | e0bd4100904f473e7364a684980f63445c06a719 (patch) | |
| tree | 25f04a97dca55288d0ce85bb6db389f4255e8c0a | |
| parent | 4d253b0c4d9564791acb79edcfb21df5ba282903 (diff) | |
| download | perlweeklychallenge-club-e0bd4100904f473e7364a684980f63445c06a719.tar.gz perlweeklychallenge-club-e0bd4100904f473e7364a684980f63445c06a719.tar.bz2 perlweeklychallenge-club-e0bd4100904f473e7364a684980f63445c06a719.zip | |
Perl & Raku solutions to Tasks 1 & 2 for Week 276
| -rw-r--r-- | challenge-276/athanasius/perl/ch-1.pl | 360 | ||||
| -rw-r--r-- | challenge-276/athanasius/perl/ch-2.pl | 209 | ||||
| -rw-r--r-- | challenge-276/athanasius/raku/ch-1.raku | 301 | ||||
| -rw-r--r-- | challenge-276/athanasius/raku/ch-2.raku | 179 |
4 files changed, 1049 insertions, 0 deletions
diff --git a/challenge-276/athanasius/perl/ch-1.pl b/challenge-276/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..584d64fbd5 --- /dev/null +++ b/challenge-276/athanasius/perl/ch-1.pl @@ -0,0 +1,360 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 276 +========================= + +TASK #1 +------- +*Complete Day* + +Submitted by: Mohammad Sajid Anwar + +You are given an array of integers, @hours. + +Write a script to return the number of pairs that forms a complete day. + + A complete day is defined as a time duration that is an exact multiple of + 24 hours. + +Example 1 + + Input: @hours = (12, 12, 30, 24, 24) + Output: 2 + + Pair 1: (12, 12) + Pair 2: (24, 24) + +Example 2 + + Input: @hours = (72, 48, 24, 5) + Output: 3 + + Pair 1: (72, 48) + Pair 2: (72, 24) + Pair 3: (48, 24) + +Example 3 + + Input: @hours = (12, 18, 24) + Output: 0 + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Assumptions +----------- +1. Hours are unsigned integers; negative hours are excluded. +2. The pair (0, 0) is accepted as a "complete day" because it meets the + definition: "a time duration that is an exact multiple of 24 hours." + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If an explanation of the output is required, the flag "--verbose" is entered + on the command-line. +3. The input hours are entered as a non-empty list of unsigned integers at the + tail of the command-line. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Getopt::Long; +use List::Util qw( uniqint ); +use Regexp::Common qw( number ); +use Test::More; + +const my $DAY => 24; +const my $HALF_DAY => int( $DAY / 2 ); +const my $USAGE => <<END; +Usage: + perl $0 [--verbose] [<hours> ...] + perl $0 + + --verbose Explain the output? [default: False] + [<hours> ...] A non-empty list of unsigned integers +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 276, Task #1: Complete Day (Perl)\n\n"; +} + +#------------------------------------------------------------------------------- +package DayPair +#------------------------------------------------------------------------------- +{ + use Moo; + use Types::Common::Numeric qw( PositiveOrZeroInt ); + use namespace::clean; + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + has lhs => + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ( + is => 'ro', + isa => PositiveOrZeroInt + ); + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + has rhs => + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ( + is => 'ro', + isa => PositiveOrZeroInt + ); + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + sub BUILD # Sanity check + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + my ($self) = @_; + + ($self->{ lhs } + $self->{ rhs }) % $DAY == 0 or die 'Invalid DayPair'; + } +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my ($verbose, $hours) = parse_command_line(); + + printf "Input: \@hours = (%s)\n", join ', ', @$hours; + + my $pairs = find_day_pairs( $hours ); + my $count = scalar @$pairs; + + print "Output: $count\n"; + + if ($verbose && $count > 0) + { + print "\n"; + + my $n = 1; + + printf( "Pair %d: (%d, %d)\n", $n++, $_->lhs, $_->rhs ) for @$pairs; + } + } +} + +#------------------------------------------------------------------------------- +sub find_day_pairs +#------------------------------------------------------------------------------- +{ + my ($hours) = @_; + my @pairs; + my @sorted_hours; + + for my $hour (@$hours) + { + my $mod = $hour % $DAY; + + push $sorted_hours[ $mod ]->@*, $hour; + } + + push @pairs, pair_identical_mods( $sorted_hours[ 0 ] ); # Mod 0 + push @pairs, pair_identical_mods( $sorted_hours[ $HALF_DAY ] ); # Mod 12 + + for my $i (1 .. $DAY - 1) + { + next if $i == $HALF_DAY; + + if ($sorted_hours[ $i ]) + { + $sorted_hours[ $i ] = + [ sort { $a <=> $b } uniqint $sorted_hours[ $i ]->@* ]; + } + } + + push @pairs, pair_complementary_mods( \@sorted_hours ); + + @pairs = sort { $b->lhs <=> $a->lhs || $b->rhs <=> $a->rhs } @pairs; + + return \@pairs; +} + +#------------------------------------------------------------------------------- +sub pair_identical_mods +#------------------------------------------------------------------------------- +{ + my ($hours_ref) = @_; + my @pairs; + + if (defined $hours_ref && scalar @$hours_ref >= 2) + { + my @hours = sort { $b <=> $a } @$hours_ref; + my $last_left; + + for my $i (0 .. $#hours - 1) + { + my $left = $hours[ $i ]; + + next if defined $last_left && $last_left == $left; + + my $last_right; + + for my $j ($i + 1 .. $#hours) + { + my $right = $hours[ $j ]; + + next if defined $last_right && $last_right == $right; + + push @pairs, DayPair->new( lhs => $left, rhs => $right ); + + $last_right = $right; + } + + $last_left = $left; + } + } + + return @pairs; +} + +#------------------------------------------------------------------------------- +sub pair_complementary_mods +#------------------------------------------------------------------------------- +{ + my ($sorted_hours) = @_; + my @pairs; + + for my $i (1 .. $HALF_DAY - 1) + { + for my $left ($sorted_hours->[ $i ]->@*) + { + my $j = $DAY - $i; + + for my $right ($sorted_hours->[ $j ]->@*) + { + my ($lhs, $rhs) = ($left > $right) ? ($left, $right) + : ($right, $left); + + push @pairs, DayPair->new( lhs => $lhs, rhs => $rhs ); + } + } + } + + return @pairs; +} + +#------------------------------------------------------------------------------- +sub parse_command_line +#------------------------------------------------------------------------------- +{ + my $verbose = 0; + + GetOptions + ( + verbose => \$verbose + ) or error( 'Error in command line arguments' ); + + my @hours = @ARGV; + + scalar @hours > 0 or error( 'Missing command-line input' ); + + for (@hours) + { + / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] ); + $_ >= 0 or error( qq["$_" is negative] ); + } + + return ($verbose, \@hours); +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + while ($line =~ / \\ $ /x) + { + $line =~ s/ \\ $ / /x; + + my $next = <DATA>; + + $next =~ s/ ^ \s+ //x; + $line .= $next; + } + + my ($test_name, $hours_str, $expected_str) = split / \| /x, $line; + + for ($test_name, $hours_str, $expected_str) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @hours = split / \s+ /x, $hours_str; + my $pairs = find_day_pairs( \@hours ); + my $expected = get_expected( $expected_str ); + + is_deeply $pairs, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub get_expected +#------------------------------------------------------------------------------- +{ + my ($expected_str) = @_; + my @expected; + + for my $pair_str (split / ; \s* /x, $expected_str) + { + my ($left, $right) = split / \s+ /x, $pair_str; + + push @expected, DayPair->new( lhs => $left, rhs => $right ); + } + + return \@expected; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1|12 12 30 24 24 |24 24; 12 12 +Example 2|72 48 24 5 |72 48; 72 24; 48 24 +Example 3|12 18 24 | +1-off | 1 23 25 47 49 71 23 23 |71 49; 71 25; 71 1; 49 47; 49 23; 47 25; \ + 47 1; 25 23; 23 1 +7-off | 7 17 17 31 65 |65 31; 65 7; 31 17; 17 7 +Combined |65 1 31 23 17 25 7 47 71|71 25; 71 1; 65 31; 65 7; 47 25; 47 1; \ + 31 17; 25 23; 23 1; 17 7 diff --git a/challenge-276/athanasius/perl/ch-2.pl b/challenge-276/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..503271fcf5 --- /dev/null +++ b/challenge-276/athanasius/perl/ch-2.pl @@ -0,0 +1,209 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 276 +========================= + +TASK #2 +------- +*Maximum Frequency* + +Submitted by: Mohammad Sajid Anwar + +You are given an array of positive integers, @ints. + +Write a script to return the total number of elements in the given array which +have the highest frequency. + +Example 1 + + Input: @ints = (1, 2, 2, 4, 1, 5) + Output: 4 + + The maximum frequency is 2. + The elements 1 and 2 has the maximum frequency. + +Example 2 + + Input: @ints = (1, 2, 3, 4, 5) + Output: 5 + + The maximum frequency is 1. + The elements 1, 2, 3, 4 and 5 has the maximum frequency. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Assumption +---------- +"Positive integers" are greater than zero. + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If an explanation of the output is required, the flag "--verbose" is entered + on the command-line. +3. The input integers are entered as a non-empty list at the end of the command- + line. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Getopt::Long; +use List::Util qw( max ); +use Regexp::Common qw( number ); +use Test::More; + +const my $USAGE => <<END; +Usage: + perl $0 [--verbose] [<ints> ...] + perl $0 + + --verbose Explain the output? [default: False] + [<ints> ...] A list of positive integers +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 276, Task #2: Maximum Frequency (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my ($verbose, $ints) = parse_command_line(); + + printf "Input: \@ints = (%s)\n", join ', ', @$ints; + + my $max = max_freq( $ints ); + + printf "Output: %d\n", $max->{ count }; + + if ($verbose) + { + printf "\nMaximum frequency: %d\n", $max->{ freq }; + + printf "Element%s with the maximum frequency: %s\n", + scalar $max->{ elems }->@* == 1 ? '' : 's', + join ', ', $max->{ elems }->@*; + } + } +} + +#------------------------------------------------------------------------------- +sub max_freq +#------------------------------------------------------------------------------- +{ + my ($ints) = @_; + my %freq; + ++$freq{ $_ } for @$ints; + + my %max = (freq => max( values %freq ), count => 0); + my %elem; + + for (@$ints) + { + if ($freq{ $_ } == $max{ freq }) + { + ++$elem{ $_ }; + ++$max{ count }; + } + } + + $max{ elems } = [ sort { $a <=> $b } keys %elem ]; + + return \%max; +} + +#------------------------------------------------------------------------------- +sub parse_command_line +#------------------------------------------------------------------------------- +{ + my $verbose = 0; + + GetOptions + ( + verbose => \$verbose + ) or error( 'Invalid command-line argument' ); + + my @ints = @ARGV; + + scalar @ints > 0 or error( 'Missing command-line input' ); + + for (@ints) + { + / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] ); + $_ > 0 or error( qq["$_" is not positive] ); + } + + return ($verbose, \@ints); +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $ints, $exp_max_freq, $elems, $exp_count) = + split / \| /x, $line; + + for ($test_name, $ints, $exp_max_freq, $elems, $exp_count) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @ints = split / \s+ /x, $ints; + my @exp_elems = split / \s+ /x, $elems; + my $max = max_freq( \@ints ); + + is $max->{ freq }, $exp_max_freq, $test_name; + is_deeply $max->{ elems }, \@exp_elems, $test_name; + is $max->{ count }, $exp_count, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1 |1 2 2 4 1 5|2|1 2 |4 +Example 2 |1 2 3 4 5 |1|1 2 3 4 5|5 +Single elem|7 3 7 5 7 9|3|7 |3 diff --git a/challenge-276/athanasius/raku/ch-1.raku b/challenge-276/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..cf5c3e4b47 --- /dev/null +++ b/challenge-276/athanasius/raku/ch-1.raku @@ -0,0 +1,301 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 276 +========================= + +TASK #1 +------- +*Complete Day* + +Submitted by: Mohammad Sajid Anwar + +You are given an array of integers, @hours. + +Write a script to return the number of pairs that forms a complete day. + + A complete day is defined as a time duration that is an exact multiple of + 24 hours. + +Example 1 + + Input: @hours = (12, 12, 30, 24, 24) + Output: 2 + + Pair 1: (12, 12) + Pair 2: (24, 24) + +Example 2 + + Input: @hours = (72, 48, 24, 5) + Output: 3 + + Pair 1: (72, 48) + Pair 2: (72, 24) + Pair 3: (48, 24) + +Example 3 + + Input: @hours = (12, 18, 24) + Output: 0 + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Assumptions +----------- +1. Hours are unsigned integers; negative hours are excluded. +2. The pair (0, 0) is accepted as a "complete day" because it meets the + definition: "a time duration that is an exact multiple of 24 hours." + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If an explanation of the output is required, the flag "--verbose" is entered + on the command-line. +3. The input hours are entered as a non-empty list of unsigned integers at the + tail of the command-line. + +=end comment +#=============================================================================== + +use Test; + +my UInt constant DAY = 24; +my UInt constant HALF-DAY = (DAY / 2).floor; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 276, Task #1: Complete Day (Raku)\n".put; +} + +#------------------------------------------------------------------------------- +class DayPair +#------------------------------------------------------------------------------- +{ + has UInt $.lhs; + has UInt $.rhs; + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + submethod TWEAK # Sanity check + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + ($!lhs + $!rhs) % DAY == 0 or die 'Invalid DayPair'; + } +} + +#=============================================================================== +multi sub MAIN +( + #| Explain the output? + + Bool:D :$verbose = False, + + #| A non-empty list of unsigned integers + + *@hours where { .elems > 0 && .all ~~ UInt:D } +) +#=============================================================================== +{ + "Input: \@hours = (%s)\n".printf: @hours.join: ', '; + + my DayPair @pairs = find-day-pairs( @hours ); + my UInt $count = @pairs.elems; + + "Output: $count".put; + + if $verbose && $count > 0 + { + put(); + my UInt $n = 1; + + "Pair %d: (%d, %d)\n".printf( $n++, .lhs, .rhs ) for @pairs; + } +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub find-day-pairs( List:D[UInt:D] $hours --> List:D[DayPair:D] ) +#------------------------------------------------------------------------------- +{ + my DayPair @pairs; + my Array[UInt] @sorted-hours = Array[UInt].new xx DAY; + + for @$hours -> UInt $hour + { + my $mod = $hour % DAY; + + @sorted-hours[ $mod ].push: $hour.Int; # Prevent creation of IntStr + } + + @pairs.push: |pair-identical-mods( @sorted-hours[ 0 ] ); # Mod 0 + @pairs.push: |pair-identical-mods( @sorted-hours[ HALF-DAY ] ); # Mod 12 + + for 1 .. @sorted-hours.end -> UInt $i + { + next if $i == HALF-DAY; + + @sorted-hours[ $i ] = Array[UInt].new: @sorted-hours[ $i ].unique.sort; + } + + @pairs.push: |pair-complementary-mods( @sorted-hours ); + + @pairs .= sort: { $^b.lhs <=> $^a.lhs || $^b.rhs <=> $^a.rhs }; + + return @pairs; +} + +#------------------------------------------------------------------------------- +sub pair-identical-mods( List:D[UInt:D] $hours --> List:D[DayPair:D] ) +#------------------------------------------------------------------------------- +{ + my DayPair @pairs; + + if $hours.elems >= 2 + { + my UInt @hours = $hours.sort: { $^b <=> $^a }; + my UInt $last-lhs; + + for 0 .. @hours.end - 1 -> UInt $i + { + my UInt $lhs = @hours[ $i ]; + + next if $last-lhs.defined && $last-lhs == $lhs; + + my UInt $last-rhs; + + for $i + 1 .. @hours.end -> UInt $j + { + my UInt $rhs = @hours[ $j ]; + + next if $last-rhs.defined && $last-rhs == $rhs; + + @pairs.push: DayPair.new: :$lhs, :$rhs; + + $last-rhs = $rhs; + } + + $last-lhs = $lhs; + } + } + + return @pairs; +} + +#------------------------------------------------------------------------------- +sub pair-complementary-mods +( + List:D[List:D[UInt:D]] $sorted-hours +--> List:D[DayPair:D] +) +#------------------------------------------------------------------------------- +{ + my DayPair @pairs; + + for 1 .. HALF-DAY - 1 -> UInt $i + { + for |@$sorted-hours[ $i ] -> UInt $left + { + my UInt $j = DAY - $i; + + for |@$sorted-hours[ $j ] -> UInt $right + { + my UInt ($lhs, $rhs) = ($left > $right) ?? ($left, $right) + !! ($right, $left); + @pairs.push: DayPair.new: :$lhs, :$rhs; + } + } + } + + return @pairs; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $hours-str, $expected-str) = $line.split: / \| /; + + for $test-name, $hours-str, $expected-str + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my UInt @hours = int-split( $hours-str ); + my DayPair @pairs = find-day-pairs( @hours ); + my DayPair @expected; + + for $expected-str.split: / \; \s* /, :skip-empty -> Str $pair-str + { + my UInt ($lhs, $rhs) = int-split( $pair-str ); + + @expected.push: DayPair.new: :$lhs, :$rhs; + } + + is-deeply @pairs, @expected, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub int-split( Str:D $str --> Seq:D[Int:D] ) +#------------------------------------------------------------------------------- +{ + return $str.split( / \s+ /, :skip-empty ).map: { .Int }; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + my Str $data = q:to/END/; + Example 1|12 12 30 24 24 |24 24; 12 12 + Example 2|72 48 24 5 |72 48; 72 24; 48 24 + Example 3|12 18 24 | + 1-off | 1 23 25 47 49 71 23 23 |71 49; 71 25; 71 1; 49 47; 49 23; \ + 47 25; 47 1; 25 23; 23 1 + 7-off | 7 17 17 31 65 |65 31; 65 7; 31 17; 17 7 + Combined |65 1 31 23 17 25 7 47 71|71 25; 71 1; 65 31; 65 7; 47 25; \ + 47 1; 31 17; 25 23; 23 1; 17 7 + END + + $data ~~ s:g/ \\ \n \s* / /; # Concatenate backslashed lines + + return $data; +} + +################################################################################ diff --git a/challenge-276/athanasius/raku/ch-2.raku b/challenge-276/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..04cfde2e7c --- /dev/null +++ b/challenge-276/athanasius/raku/ch-2.raku @@ -0,0 +1,179 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 276 +========================= + +TASK #2 +------- +*Maximum Frequency* + +Submitted by: Mohammad Sajid Anwar + +You are given an array of positive integers, @ints. + +Write a script to return the total number of elements in the given array which +have the highest frequency. + +Example 1 + + Input: @ints = (1, 2, 2, 4, 1, 5) + Output: 4 + + The maximum frequency is 2. + The elements 1 and 2 has the maximum frequency. + +Example 2 + + Input: @ints = (1, 2, 3, 4, 5) + Output: 5 + + The maximum frequency is 1. + The elements 1, 2, 3, 4 and 5 has the maximum frequency. + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Assumption +---------- +"Positive integers" are greater than zero. + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If an explanation of the output is required, the flag "--verbose" is entered + on the command-line. +3. The input integers are entered as a non-empty list at the end of the command- + line. + +=end comment +#=============================================================================== + +use Test; + +subset Pos of Int where * > 0; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 276, Task #2: Maximum Frequency (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + Bool:D :$verbose = False, #= Explain the output? + + *@ints where { .elems > 0 && .all ~~ Pos:D } #= A list of positive integers +) +#=============================================================================== +{ + "Input: \@ints = (%s)\n".printf: @ints.join: ', '; + + my %max = max-freq( @ints ); + + "Output: %d\n".printf: %max< count >; + + if $verbose + { + "\nMaximum frequency: %d\n".printf: %max< freq >; + + "Element%s with the maximum frequency: %s\n".printf: + %max< elems >.elems == 1 ?? '' !! 's', %max< elems >.join: ', '; + } +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub max-freq( List:D[Pos:D] $ints --> Hash:D ) +#------------------------------------------------------------------------------- +{ + my UInt %freq{Pos}; + ++%freq{ $_ } for @$ints; + + my %max = freq => %freq<>:v.max, count => 0; + + my UInt %elem{Pos}; + + for @$ints + { + if %freq{ $_ } == %max< freq > + { + ++%elem{ $_ }; + ++%max< count >; + } + } + + %max< elems > = Array[Pos].new: %elem<>:k.sort; + + return %max; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $ints, $exp-max-freq, $elems, $exp-count) = + $line.split: / \| /; + + for $test-name, $ints, $exp-max-freq, $elems, $exp-count + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Pos @ints = $ints\.split( / \s+ /, :skip-empty ).map: { .Int }; + my Pos @exp-elems = $elems.split( / \s+ /, :skip-empty ).map: { .Int }; + my %max = max-freq( @ints ); + + is %max< freq >, $exp-max-freq.Int, $test-name; + is-deeply %max< elems >, @exp-elems, $test-name; + is %max< count >, $exp-count.Int, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +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 |1 2 2 4 1 5|2|1 2 |4 + Example 2 |1 2 3 4 5 |1|1 2 3 4 5|5 + Single elem|7 3 7 5 7 9|3|7 |3 + END +} + +################################################################################ |
