diff options
| author | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2023-01-08 22:02:54 +1000 |
|---|---|---|
| committer | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2023-01-08 22:02:54 +1000 |
| commit | 18f15abfd63dd65c6d79f446c0381856df7e1d44 (patch) | |
| tree | 466a24128a061bf2569258ecd0abea06f1b2f3d5 | |
| parent | 30bc90811147ec3a3ccfefa2dff445fee9225d9d (diff) | |
| download | perlweeklychallenge-club-18f15abfd63dd65c6d79f446c0381856df7e1d44.tar.gz perlweeklychallenge-club-18f15abfd63dd65c6d79f446c0381856df7e1d44.tar.bz2 perlweeklychallenge-club-18f15abfd63dd65c6d79f446c0381856df7e1d44.zip | |
Perl & Raku solutions to Tasks 1 & 2 for Week 198
| -rw-r--r-- | challenge-198/athanasius/perl/ch-1.pl | 174 | ||||
| -rw-r--r-- | challenge-198/athanasius/perl/ch-2.pl | 157 | ||||
| -rw-r--r-- | challenge-198/athanasius/raku/ch-1.raku | 196 | ||||
| -rw-r--r-- | challenge-198/athanasius/raku/ch-2.raku | 188 |
4 files changed, 715 insertions, 0 deletions
diff --git a/challenge-198/athanasius/perl/ch-1.pl b/challenge-198/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..8fc6f57582 --- /dev/null +++ b/challenge-198/athanasius/perl/ch-1.pl @@ -0,0 +1,174 @@ +#!perl + +############################################################################### +=comment + +Perl Weekly Challenge 198 +========================= + +TASK #1 +------- +*Max Gap* + +Submitted by: Mohammad S Anwar + +You are given a list of integers, @list. + +Write a script to find the total pairs in the sorted list where 2 consecutive +elements has the max gap. If the list contains less then 2 elements then return +0. + +Example 1 + + Input: @list = (2,5,8,1) + Output: 2 + + Since the sorted list (1,2,5,8) has 2 such pairs (2,5) and (5,8) + +Example 2 + + Input: @list = (3) + Output: 0 + +=cut +############################################################################### + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. +2. If $VERBOSE is set to a true value, an explanation like that in Example 1 is + added to the solution. + +=cut +#============================================================================== + +use strict; +use warnings; +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $TEST_FIELDS => 3; +const my $VERBOSE => 1; +const my $USAGE => +"Usage: + perl $0 [<list> ...] + perl $0 + + [<list> ...] A list of 1 or more integers\n"; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + $| = 1; + print "\nChallenge 198, Task #1: Max Gap (Perl)\n\n"; +} + +#============================================================================== +MAIN: +#============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my @list = @ARGV; + + for (@list) + { + / ^ $RE{num}{int} $ /x + or die qq[ERROR: "$_" is not a valid integer\n$USAGE]; + } + + printf "Input: \@list = (%s)\n", join ', ', @list; + + my ($max_pairs, $max_gap, $pairs) = max_gap( @list ); + + print "Output: $max_pairs\n"; + + if ($VERBOSE && scalar @list > 1) + { + printf "\nSince the sorted list (%s) has %d pair%s with the " . + "maximum gap of %d:\n%s\n", + join( ',', sort { $a <=> $b } @list ), + $max_pairs, + ($max_pairs == 1 ? '' : 's'), + $max_gap, + join( ', ', map { '(' . join( ',', @$_ ) . ')' } @$pairs ); + } + } +} + +#------------------------------------------------------------------------------ +sub max_gap +#------------------------------------------------------------------------------ +{ + my @list = @_; + my @sorted = sort { $a <=> $b } @list; + my ($max_gap, $max_pairs, @pairs) = (-1, 0, ()); + + for my $i (0 .. $#sorted - 1) + { + my $gap = $sorted[ $i + 1 ] - $sorted[ $i ]; + + if ($gap > $max_gap) + { + $max_gap = $gap; + $max_pairs = 1; + @pairs = [ @sorted[ $i, $i + 1 ] ]; + } + elsif ($gap == $max_gap) + { + ++$max_pairs; + push @pairs, [ @sorted[ $i, $i + 1 ] ]; + } + } + + return ($max_pairs, $max_gap, \@pairs); +} + +#------------------------------------------------------------------------------ +sub run_tests +#------------------------------------------------------------------------------ +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $input, $expected) = split /\|/, $line, $TEST_FIELDS; + + $input =~ s/ ^ \s* (.+?) \s* $ /$1/x; # Trim whitespace + $expected =~ s/ ^ \s* (.+?) \s* $ /$1/x; + $expected =~ s/ \s+ / /gx; + + my @list = split / , \s+ /x, $input; + + my ($max_pairs, undef, undef) = max_gap( @list ); + + my $got = join ', ', $max_pairs; + + is $got, $expected, $test_name; + } + + done_testing; +} + +############################################################################### + +__DATA__ +Example 1| 2, 5, 8, 1 |2 +Example 2| 3 |0 +Negatives|-5, -1, -3 |2 +Mixed |-3, 4, 2, -1, 1|3 diff --git a/challenge-198/athanasius/perl/ch-2.pl b/challenge-198/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..06e53e858e --- /dev/null +++ b/challenge-198/athanasius/perl/ch-2.pl @@ -0,0 +1,157 @@ +#!perl + +############################################################################### +=comment + +Perl Weekly Challenge 198 +========================= + +TASK #2 +------- +*Prime Count* + +Submitted by: Mohammad S Anwar + +You are given an integer $n > 0. + +Write a script to print the count of primes less than $n. + +Example 1 + + Input: $n = 10 + Output: 4 as in there are 4 primes less than 10 are 2, 3, 5, 7. + +Example 2 + + Input: $n = 15 + Output: 6 + +Example 3 + + Input: $n = 1 + Output: 0 + +Example 4 + + Input: $n = 25 + Output: 9 + +=cut +############################################################################### + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=comment + +Interface +--------- +If no command-line argument is given, the test suite is run. + +=cut +#============================================================================== + +use strict; +use warnings; +use Const::Fast; +use ntheory qw( prime_count ); +use Regexp::Common qw( number ); +use Test::More; + +const my $TEST_FIELDS => 3; +const my $USAGE => +"Usage: + perl $0 [<list> ...] + perl $0 + + [<list> ...] An integer greater than zero\n"; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + $| = 1; + print "\nChallenge 198, Task #2: Prime Count (Perl)\n\n"; +} + +#============================================================================== +MAIN: +#============================================================================== +{ + my $args = scalar @ARGV; + + if ($args == 0) + { + run_tests(); + } + elsif ($args == 1) + { + my $n = $ARGV[ 0 ]; + + $n =~ / ^ $RE{num}{int} $ /x + or error( qq["$_" is not a valid integer] ); + + $n > 0 or error( "$n is not greater than zero" ); + + print "Input: \$n = $n\n"; + printf "Output: %d\n", count_primes( $n ); + } + else + { + error( "Expected 1 or 0 command line arguments, found $args" ); + } +} + +#------------------------------------------------------------------------------ +sub count_primes +#------------------------------------------------------------------------------ +{ + my ($n) = @_; + + # Note: The count returned by Math::Prime::Util::prime_count( $x ) is + # *inclusive* of $x + + return prime_count( $n - 1 ); +} + +#------------------------------------------------------------------------------ +sub error +#------------------------------------------------------------------------------ +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +#------------------------------------------------------------------------------ +sub run_tests +#------------------------------------------------------------------------------ +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $n, $expected) = split / \| /x, $line, $TEST_FIELDS; + + s/ ^ \s* (.+?) \s* $ /$1/x # Trim whitespace + for $test_name, $n, $expected; + + is count_primes( $n ), $expected, $test_name; + } + + done_testing; +} + +############################################################################### + +__DATA__ +Example 1| 10| 4 +Example 2| 15| 6 +Example 3| 1| 0 +Example 4| 25| 9 +Large n | 1000000| 78498 +Huge n |1234567890|62106578 diff --git a/challenge-198/athanasius/raku/ch-1.raku b/challenge-198/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..661569d567 --- /dev/null +++ b/challenge-198/athanasius/raku/ch-1.raku @@ -0,0 +1,196 @@ +use v6d; + +############################################################################### +=begin comment + +Perl Weekly Challenge 198 +========================= + +TASK #1 +------- +*Max Gap* + +Submitted by: Mohammad S Anwar + +You are given a list of integers, @list. + +Write a script to find the total pairs in the sorted list where 2 consecutive +elements has the max gap. If the list contains less then 2 elements then return +0. + +Example 1 + + Input: @list = (2,5,8,1) + Output: 2 + + Since the sorted list (1,2,5,8) has 2 such pairs (2,5) and (5,8) + +Example 2 + + Input: @list = (3) + Output: 0 + +=end comment +############################################################################### + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. +2. If the first argument is negative, it must be preceded by "--" to distin- + guish it from a command-line flag. +3. If $VERBOSE is set to True, an explanation like that in Example 1 is added + to the solution. + +=end comment +#============================================================================== + +use Test; + +my UInt constant $TEST-FIELDS = 3; +my Bool constant $VERBOSE = True; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + "\nChallenge 198, Task #1: Max Gap (Raku)\n".put; +} + +#============================================================================== +multi sub MAIN +( + #| A list of 1 or more integers + + *@list where { .elems >= 1 && .all ~~ Int:D } +) +#============================================================================== +{ + "Input: \@list = (%s)\n".printf: @list.join: ', '; + + my (UInt $max-pairs, Int $max-gap, Array[Array[Int]] $pairs) = + max-gap( @list ); + + "Output: $max-pairs".put; + + if $VERBOSE && @list.elems > 1 + { + ("\nSince the sorted list (%s) has %d pair%s with the maximum gap " ~ + "of %d:\n%s\n").printf: + @list.sort.join( ',' ), + $max-pairs, + ($max-pairs == 1 ?? '' !! 's'), + $max-gap, + @$pairs.map( { '(' ~ @$_.join( ',' ) ~ ')' } ).join: ', '; + } +} + +#============================================================================== +multi sub MAIN() # No input: run the test suite +#============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------ +sub max-gap +( + List:D[Int:D] $list +--> List:D[UInt:D, Int:D, List:D[List:D[Int:D]]] +) +#------------------------------------------------------------------------------ +{ + my Int @sorted = $list.sort; + my Int $max-gap = -1; + my UInt $max-pairs = 0; + my Array[Int] @pairs; + + for 0 .. @sorted.end - 1 -> UInt $i + { + my UInt $gap = @sorted[ $i + 1 ] - @sorted[ $i ]; + + if $gap > $max-gap + { + $max-gap = $gap; + $max-pairs = 1; + @pairs = Empty; + @pairs.push: Array[Int].new: @sorted[ $i, $i + 1 ]; + } + elsif $gap == $max-gap + { + ++$max-pairs; + @pairs.push: Array[Int].new: @sorted[ $i, $i + 1 ]; + } + } + + return $max-pairs, $max-gap, @pairs; +} + +#------------------------------------------------------------------------------ +sub run-tests() +#------------------------------------------------------------------------------ +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $input, $expected) = + $line.split: / \| /, $TEST-FIELDS; + + $input ~~ s/ ^ \s* (.+?) \s* $ /$0/; # Trim whitespace + $expected ~~ s/ ^ \s* (.+?) \s* $ /$0/; + $expected ~~ s:g/ \s+ / /; + + my Int @list = $input.split( / \, \s* / ).map: { .Int }; + + my (UInt $max-pairs, $, $) = max-gap( @list ); + + my Str $got = $max-pairs.join: ', '; + + is $got, $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| 2, 5, 8, 1 |2 + Example 2| 3 |0 + Negatives|-5, -1, -3 |2 + Mixed |-3, 4, 2, -1, 1|3 + END +} + +############################################################################### diff --git a/challenge-198/athanasius/raku/ch-2.raku b/challenge-198/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..3d6f4f5d02 --- /dev/null +++ b/challenge-198/athanasius/raku/ch-2.raku @@ -0,0 +1,188 @@ +use v6d; + +############################################################################### +=begin comment + +Perl Weekly Challenge 198 +========================= + +TASK #2 +------- +*Prime Count* + +Submitted by: Mohammad S Anwar + +You are given an integer $n > 0. + +Write a script to print the count of primes less than $n. + +Example 1 + + Input: $n = 10 + Output: 4 as in there are 4 primes less than 10 are 2, 3, 5, 7. + +Example 2 + + Input: $n = 15 + Output: 6 + +Example 3 + + Input: $n = 1 + Output: 0 + +Example 4 + + Input: $n = 25 + Output: 9 + +=end comment +############################################################################### + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=begin comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +Algorithm +--------- +Neither Inline::Perl5 (for Math::Prime::Util/ntheory) nor Math::Primesieve will +(currently) install on my Rakudo platform. I have therefore implemented a Sieve +of Eratosthenes [1] to generate primes up to the given n. + +This performs well for small values of n, but is quite slow for larger values: +e.g., for n = one million, the sieve takes about 24 seconds. By comparison, the +ntheory::prime_count() function takes about 0.005 seconds for the same n. + +Reference +--------- +[1] "Sieve of Eratosthenes", Wikipedia, + https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + +=end comment +#============================================================================== + +use Test; + +my UInt constant $TEST-FIELDS = 3; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + "\nChallenge 198, Task #2: Prime Count (Raku)\n".put; +} + +#============================================================================== +multi sub MAIN +( + UInt:D $n where { $n > 0 } #= An integer greater than zero +) +#============================================================================== +{ + "Input: \$n = $n".put; + + "Output: %d\n".printf: count-primes( $n ); +} + +#============================================================================== +multi sub MAIN() # Run the test suite +#============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------ +sub count-primes( UInt:D $n where { $n > 0 } --> UInt:D ) +#------------------------------------------------------------------------------ +{ + my UInt $count = 0; + my Bool @sieve = |(False xx 2), |(True xx ($n - 2)); + my UInt $sqrt-n = $n.sqrt.floor; + + for 2 .. $sqrt-n -> UInt $i + { + if @sieve[ $i ] + { + ++$count; + + for 0 .. * -> UInt $j + { + my UInt $k = $i² + $j * $i; + + last if $k >= $n; + + @sieve[ $k ] = False; + } + } + } + + for $sqrt-n + 1 .. $n - 1 -> UInt $m + { + ++$count if @sieve[ $m ]; + } + + return $count; +} + +#------------------------------------------------------------------------------ +sub run-tests() +#------------------------------------------------------------------------------ +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $n, $expected) = $line.split: / \| /, $TEST-FIELDS; + + s/ ^ \s* (.+?) \s* $ /$0/ # Trim whitespace + for $test-name, $n, $expected; + + is count-primes( $n.Int ), $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| 10| 4 + Example 2| 15| 6 + Example 3| 1| 0 + Example 4| 25| 9 + Large n |1000000|78498 + END +} + +############################################################################### |
