diff options
| author | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2023-05-22 02:34:49 +1000 |
|---|---|---|
| committer | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2023-05-22 02:34:49 +1000 |
| commit | 697ccec10af0587d98a25523f958504027135ead (patch) | |
| tree | 056535ab5d7e77188aa3282229f8bc07eb3fdff5 | |
| parent | c4b5be7c34b100fcda4b1e2481df1e497a7d2661 (diff) | |
| download | perlweeklychallenge-club-697ccec10af0587d98a25523f958504027135ead.tar.gz perlweeklychallenge-club-697ccec10af0587d98a25523f958504027135ead.tar.bz2 perlweeklychallenge-club-697ccec10af0587d98a25523f958504027135ead.zip | |
Perl & Raku solutions to Task 1 for Week 217
| -rw-r--r-- | challenge-217/athanasius/perl/ch-1.pl | 261 | ||||
| -rw-r--r-- | challenge-217/athanasius/raku/ch-1.raku | 255 |
2 files changed, 516 insertions, 0 deletions
diff --git a/challenge-217/athanasius/perl/ch-1.pl b/challenge-217/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..28ba086c1b --- /dev/null +++ b/challenge-217/athanasius/perl/ch-1.pl @@ -0,0 +1,261 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 217 +========================= + +TASK #1 +------- +*Sorted Matrix* + +Submitted by: Mohammad S Anwar + +You are given a n x n matrix where n >= 2. + +Write a script to find 3rd smallest element in the sorted matrix. + +Example 1 + + Input: @matrix = ([3, 1, 2], [5, 2, 4], [0, 1, 3]) + Output: 1 + + The sorted list of the given matrix: 0, 1, 1, 2, 2, 3, 3, 4, 5. + The 3rd smallest of the sorted list is 1. + +Example 2 + + Input: @matrix = ([2, 1], [4, 5]) + Output: 4 + + The sorted list of the given matrix: 1, 2, 4, 5. + The 3rd smallest of the sorted list is 4. + +Example 3 + + Input: @matrix = ([1, 0, 3], [0, 0, 0], [1, 2, 1]) + Output: 0 + + The sorted list of the given matrix: 0, 0, 0, 0, 1, 1, 1, 2, 3. + The 3rd smallest of the sorted list is 0. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If $VERBOSE is set to a true value (the default), the output is followed by + an explanation of the result. + +Assumption +---------- +Matrix elements are integers. + +=cut +#=============================================================================== + +use strict; +use warnings; +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $VERBOSE => 1; +const my $USAGE => +"Usage: + perl $0 <matrix> + perl $0 + + <matrix> String representation of an n x n integer matrix where n >= 2 +"; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 217, Task #1: Sorted Matrix (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + my $args = scalar @ARGV; + + if ($args == 0) + { + run_tests(); + } + elsif ($args == 1) + { + my $matrix = parse_matrix_string( $ARGV[ 0 ] ); + + printf "Input: \@matrix = %s\n", format_matrix( $matrix ); + + my @elements; + my $third_smallest = find_third_smallest( $matrix, \@elements ); + + printf "Output: %d\n", $third_smallest; + + if ($VERBOSE) + { + printf "\nThe sorted list of the given matrix: %s\n", + join ', ', @elements; + + my $padding = length( $elements[ 0 ] ) + + length( $elements[ 1 ] ) + 4; + + printf "The third-smallest element: %s%s\n", + ' ' x $padding, '^' x length $third_smallest; + } + } + else + { + error( "Expected 0 or 1 command-line arguments, found $args" ); + } +} + +#------------------------------------------------------------------------------- +sub find_third_smallest +#------------------------------------------------------------------------------- +{ + my ($matrix, $elements_ref) = @_; + my @elements; + + push @elements, @$_ for @$matrix; + + @elements = sort { $a <=> $b } @elements; + + scalar @elements >= 3 or error( 'Matrix too small' ); + + @$elements_ref = @elements if $elements_ref; + + return $elements[ 2 ]; +} + +#------------------------------------------------------------------------------- +sub parse_matrix_string +#------------------------------------------------------------------------------- +{ + my ($matrix) = @_; + + $matrix =~ / ^ \s* \( (.*?) \s* \) \s* $ /x + or error( 'Invalid input string' ); + + my $body = $1; + my @matrix; + + while ($body =~ / \[ (.+?) \] /gx) + { + my $row = $1; + my @elems = split / , \s* /x, $row; + + for my $elem (@elems) + { + $elem =~ s/ ^ \s+ //x; + $elem =~ s/ \s+ $ //x; + $elem =~ m/ ^ $RE{num}{int} $ /x + or error( qq["$elem" is not a valid integer] ); + } + + push @matrix, [ @elems ]; + + } + + validate_matrix( \@matrix ); + + return \@matrix; +} + +#------------------------------------------------------------------------------- +sub validate_matrix +#------------------------------------------------------------------------------- +{ + my ($matrix) = @_; + + my $rows = scalar @$matrix; + my $n = scalar @{ $matrix->[ 0 ] }; + + $rows >= 2 or error( 'Too few rows in matrix' ); + $rows == $n or error( 'Matrix is not square' ); + + for my $i (1 .. $#$matrix) + { + my $m = scalar @{ $matrix->[ $i ] }; + my $j = $i + 1; + + $m == $n or error( "In matrix row $j: expected $n elements, found $m" ); + } +} + +#------------------------------------------------------------------------------- +sub format_matrix +#------------------------------------------------------------------------------- +{ + my ($matrix) = @_; + my $matrix_str = '('; + my @row_strs; + + for my $elems (@$matrix) + { + push @row_strs, '[' . join( ', ', @$elems ) . ']'; + } + + $matrix_str .= join( ', ', @row_strs ) . ')'; + + return $matrix_str; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $matrix_str, $expected) = split / \| /x, $line; + + for ($test_name, $matrix_str, $expected) # Trim whitespace + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @matrix = parse_matrix_string( $matrix_str ); + my $third_smallest = find_third_smallest( @matrix ); + + is $third_smallest, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1|([3, 1, 2], [5, 2, 4], [ 0, 1, 3])| 1 +Example 2|([2, 1], [4, 5]) | 4 +Example 3|([1, 0, 3], [0, 0, 0], [ 1, 2, 1])| 0 +Negatives|([0, -1, -2], [0, -1, -3], [-3, 1, 2])|-2 diff --git a/challenge-217/athanasius/raku/ch-1.raku b/challenge-217/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..43e9d9e547 --- /dev/null +++ b/challenge-217/athanasius/raku/ch-1.raku @@ -0,0 +1,255 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 217 +========================= + +TASK #1 +------- +*Sorted Matrix* + +Submitted by: Mohammad S Anwar + +You are given a n x n matrix where n >= 2. + +Write a script to find 3rd smallest element in the sorted matrix. + +Example 1 + + Input: @matrix = ([3, 1, 2], [5, 2, 4], [0, 1, 3]) + Output: 1 + + The sorted list of the given matrix: 0, 1, 1, 2, 2, 3, 3, 4, 5. + The 3rd smallest of the sorted list is 1. + +Example 2 + + Input: @matrix = ([2, 1], [4, 5]) + Output: 4 + + The sorted list of the given matrix: 1, 2, 4, 5. + The 3rd smallest of the sorted list is 4. + +Example 3 + + Input: @matrix = ([1, 0, 3], [0, 0, 0], [1, 2, 1]) + Output: 0 + + The sorted list of the given matrix: 0, 0, 0, 0, 1, 1, 1, 2, 3. + The 3rd smallest of the sorted list is 0. + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2023 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. If VERBOSE is set to True (the default), the output is followed by an explan- + ation of the result + +Assumption +---------- +Matrix elements are integers. + +=end comment +#=============================================================================== + +use Test; + +subset Result of List where (Int, Array[Int]); + +my Bool constant VERBOSE = True; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 217, Task #1: Sorted Matrix (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + #| String representation of an n x n integer matrix where n >= 2 + + Str:D $matrix +) +#=============================================================================== +{ + my Array[Int] @matrix = parse-matrix-string( $matrix ); + + "Input: \@matrix = %s\n".printf: format-matrix( @matrix ); + + my Result $result = find-third-smallest( @matrix ); + + "Output: %d\n".printf: $result[ 0 ]; + + if VERBOSE + { + my Int @elements = $result[ 1 ]; + + "\nThe sorted list of the given matrix: %s\n".printf: + @elements.join: ', '; + + my UInt $padding = @elements[ 0 ].chars + @elements[ 1 ].chars + 4; + + "The third-smallest element: %s%s\n".printf: + ' ' x $padding, '^' x $result[ 0 ].chars; + } +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub find-third-smallest( List:D[List:D[Int:D]] $matrix --> Result:D ) +#------------------------------------------------------------------------------- +{ + my Int @elements; + + @elements.push: |$_ for @$matrix; + + @elements.= sort; + + @elements.elems >= 3 or error( 'Matrix too small' ); + + return @elements[ 2 ], @elements; +} + +#=============================================================================== +grammar Matrix +#=============================================================================== +{ + token TOP { ^ \s* '(' \s* [ <row> <sep> ]+ <row> \s* ')' \s* $ } + token row { '[' \s* [ <elem> <sep> ]+ <elem> \s* ']' } + token elem { <[-+]>? <[0..9]>+ } + token sep { \, \s* } +} + +#------------------------------------------------------------------------------- +sub parse-matrix-string( Str:D $matrix --> List:D[List:D[Int:D]] ) +#------------------------------------------------------------------------------- +{ + my Matrix $parsed = Matrix.parse( $matrix ) + or error( 'Invalid input string' ); + + my Array[Int] @matrix; + my Str @rows = $parsed< row >.map: { .Str }; + + for @rows -> Str $row + { + $row ~~ / ^ \[ \s* (.+?) \s* \] $ /; + + @matrix.push: Array[Int].new: $0.Str.split( / \, \s* / ).map: { .Int }; + } + + validate-matrix( @matrix ); + + return @matrix; +} + +#------------------------------------------------------------------------------- +sub validate-matrix( List:D[List:D[Int:D]] $matrix ) +#------------------------------------------------------------------------------- +{ + my UInt $rows = $matrix.elems; + my UInt $n = $matrix[ 0 ].elems; + + $rows >= 2 or error( 'Too few rows in matrix' ); + $rows == $n or error( 'Matrix is not square' ); + + for 1 .. $matrix.end -> UInt $i + { + my UInt $m = $matrix[ $i ].elems; + my UInt $j = $i + 1; + + $m == $n or error( "In matrix row $j: expected $n elements, found $m" ); + } +} + +#------------------------------------------------------------------------------- +sub format-matrix( List:D[List:D[Int:D]] $matrix --> Str:D ) +#------------------------------------------------------------------------------- +{ + my Str $matrix-str = '('; + my Str @row-strs; + + for @$matrix -> Int @elems + { + @row-strs.push: '[' ~ @elems.join( ', ' ) ~ ']'; + } + + $matrix-str ~= @row-strs.join( ', ' ) ~ ')'; + + return $matrix-str; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $matrix-str, $expected) = $line.split: / \| /; + + s/ \s+ $ // for $test-name, $matrix-str; # Trim whitespace + + my Array[Int] @matrix = parse-matrix-string( $matrix-str ); + my Result $result = find-third-smallest( @matrix ); + + is $result[ 0 ], $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|([3, 1, 2], [5, 2, 4], [ 0, 1, 3])| 1 + Example 2|([2, 1], [4, 5]) | 4 + Example 3|([1, 0, 3], [0, 0, 0], [ 1, 2, 1])| 0 + Negatives|([0, -1, -2], [0, -1, -3], [-3, 1, 2])|-2 + END +} + +################################################################################ |
