aboutsummaryrefslogtreecommitdiff
path: root/challenge-106/athanasius
diff options
context:
space:
mode:
authorPerlMonk Athanasius <PerlMonk.Athanasius@gmail.com>2021-04-04 23:16:31 +1000
committerPerlMonk Athanasius <PerlMonk.Athanasius@gmail.com>2021-04-04 23:16:31 +1000
commitae2c69e4bca63b7311e2c1eafdf2dc9cb1a36889 (patch)
treec68907212c77bbb11314f19a10be9fad97c737a7 /challenge-106/athanasius
parentd5ff10db3ea3e9e6e150316af0d4e4c0e2a37fe1 (diff)
downloadperlweeklychallenge-club-ae2c69e4bca63b7311e2c1eafdf2dc9cb1a36889.tar.gz
perlweeklychallenge-club-ae2c69e4bca63b7311e2c1eafdf2dc9cb1a36889.tar.bz2
perlweeklychallenge-club-ae2c69e4bca63b7311e2c1eafdf2dc9cb1a36889.zip
Perl & Raku solutions to Tasks 1 & 2 of the Perl Weekly Challenge #106
On branch branch-for-challenge-106 Changes to be committed: new file: challenge-106/athanasius/perl/ch-1.pl new file: challenge-106/athanasius/perl/ch-2.pl new file: challenge-106/athanasius/raku/ch-1.raku new file: challenge-106/athanasius/raku/ch-2.raku
Diffstat (limited to 'challenge-106/athanasius')
-rw-r--r--challenge-106/athanasius/perl/ch-1.pl144
-rw-r--r--challenge-106/athanasius/perl/ch-2.pl157
-rw-r--r--challenge-106/athanasius/raku/ch-1.raku106
-rw-r--r--challenge-106/athanasius/raku/ch-2.raku83
4 files changed, 490 insertions, 0 deletions
diff --git a/challenge-106/athanasius/perl/ch-1.pl b/challenge-106/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..a4015e4dd0
--- /dev/null
+++ b/challenge-106/athanasius/perl/ch-1.pl
@@ -0,0 +1,144 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 106
+=========================
+
+Task #1
+-------
+*Maximum Gap*
+
+Submitted by: Mohammad S Anwar
+
+You are given an array of integers @N.
+
+Write a script to display the maximum difference between two successive
+elements once the array is sorted.
+
+If the array contains only 1 element then display 0.
+
+Example
+
+ Input: @N = (2, 9, 3, 5)
+ Output: 4
+
+ Input: @N = (1, 3, 8, 2, 0)
+ Output: 5
+
+ Input: @N = (5)
+ Output: 0
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2021 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Algorithm
+---------
+Straightforward: Sort the array in ascending order, then iterate through all
+pairs of adjacent elements and record the largest gap. Default to zero if there
+is only one element in the array.
+
+Note on Duplicates
+------------------
+For large arrays containing many duplicate elements, it might be possible to
+obtain a small speed-up by removing duplicates from the sorted array before
+testing adjacent elements. The (optional) flag --u[nique] (or just -u) is
+provided for this purpose. It defaults to a false value, since for small arrays
+the speed-up is likely more than outweighed by the overhead of duplicate
+removal.
+
+Command Line Usage
+------------------
+Note that if the --unique flag is given and the list contains negative numbers,
+the list must be preceded by -- to prevent the minus sign from being interpret-
+ed as introducing a command line option.
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Getopt::Long;
+use List::Util qw( uniqint );
+use Regexp::Common qw( number );
+
+const my $USAGE =>
+"Usage:
+ perl $0 [--unique --] [<N> ...]
+
+ --unique (Optional) remove duplicates
+ [<N> ...] A non-empty, unsorted list of integers\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 106, Task #1: Maximum Gap (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my ($unique, $N) = parse_command_line();
+
+ printf "Input: \@N = (%s)\n", join ', ', @$N;
+
+ my @sorted = sort { $a <=> $b } @$N; # Sort ascending
+ @sorted = uniqint @sorted if $unique; # Optionally remove dups
+ my $max_gap = 0;
+
+ # Test every difference between successive elements in the sorted array
+
+ for my $i (1 .. $#sorted)
+ {
+ my $diff = $sorted[ $i ] - $sorted[ $i - 1 ];
+
+ $max_gap = $diff if $diff > $max_gap;
+ }
+
+ print "Output: $max_gap\n";
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ my $unique = 0;
+
+ GetOptions( 'unique' => \$unique )
+ or error( 'Unrecognized command line argument' );
+
+ my @N = @ARGV;
+
+ scalar @N > 0 or error( 'Empty list' );
+
+ for my $n (@N)
+ {
+ $n =~ / ^ $RE{num}{int} $ /x
+ or error( qq[List element "$n" is not an integer] );
+ }
+
+ return ($unique, \@N);
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+###############################################################################
diff --git a/challenge-106/athanasius/perl/ch-2.pl b/challenge-106/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..4c3c538170
--- /dev/null
+++ b/challenge-106/athanasius/perl/ch-2.pl
@@ -0,0 +1,157 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 106
+=========================
+
+*Decimal String*
+
+Submitted by: Mohammad S Anwar
+
+You are given numerator and denominator i.e. $N and $D.
+
+Write a script to convert the fraction into decimal string. If the fractional
+part is recurring then put it in parenthesis.
+
+Example
+
+ Input: $N = 1, $D = 3
+ Output: "0.(3)"
+
+ Input: $N = 1, $D = 2
+ Output: "0.5"
+
+ Input: $N = 5, $D = 66
+ Output: "0.0(75)"
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2021 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Algorithm
+---------
+Neither Perl itself nor the core Math::BigRat module have an equivalent to the
+Raku base-repeating() method. Nor, to my surprise, am I able to find a CPAN
+module which provides this functionality. So I ported to Perl the Raku source
+code in rakudo-2021.03/src/core.c/Rational.pm6.
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use List::MoreUtils qw( first_index );
+use Math::BigRat;
+use POSIX qw( floor );
+use Regexp::Common qw( number );
+
+const my $BASE => 10;
+const my $USAGE =>
+"Usage:
+ perl $0 <N> <D>
+
+ <N> Numerator (an integer)
+ <D> Denominator (a non-zero integer)\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 106, Task #2: Decimal String (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my ($N, $D) = parse_command_line();
+
+ print "Input: \$N = $N, \$D = $D\n";
+
+ my ($non_rep, $rep) = base_repeating( $N, $D, $BASE );
+
+ printf qq[Output: "%s%s"\n], $non_rep, $rep ? "($rep)" : '';
+}
+
+#------------------------------------------------------------------------------
+# Adapted from rakudo-2021.03/src/core.c/Rational.pm6
+#
+sub base_repeating
+#------------------------------------------------------------------------------
+{
+ my ($N, $D, $base) = @_;
+
+ return (0, '') if $N == 0;
+
+ # Reduce to normal (i.e., shortest) form
+
+ my $rat = Math::BigRat->new( "$N / $D" ); # Implicitly calls $rat->bnorm()
+ my $num = abs $rat->numerator;
+ my $den = abs $rat->denominator;
+
+ return ('-' x ($rat < 0) . $num, '') if $den == 1;
+
+ my @quotients = floor( $num / $den );
+ my (@remainders, %remainders);
+
+ while (1)
+ {
+ push @remainders, $num %= $den;
+ last if $remainders{ $num }++ || $num == 0;
+ $num *= $base;
+ push @quotients, floor( $num / $den );
+ }
+
+ my ($rep, @cycle) = ('', ());
+
+ if ($num)
+ {
+ @cycle = splice @quotients, 1 + first_index { $_ == $num } @remainders;
+ $rep = join '', @cycle;
+ }
+
+ splice @quotients, 1, 0, '.';
+
+ my $non_rep = '-' x ($rat < 0) . join '', @quotients;
+
+ return ($non_rep, $rep);
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ my $c = scalar @ARGV;
+ $c == 2 or error( "Expected 2 command line arguments, found $c" );
+
+ for (@ARGV)
+ {
+ / ^ $RE{num}{int} $ /x
+ or error( qq["$_" is not an integer] );
+ }
+
+ $ARGV[ 1 ] == 0 and error( 'The denominator cannot be zero' );
+
+ return @ARGV;
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+###############################################################################
diff --git a/challenge-106/athanasius/raku/ch-1.raku b/challenge-106/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..5b267c60f6
--- /dev/null
+++ b/challenge-106/athanasius/raku/ch-1.raku
@@ -0,0 +1,106 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 106
+=========================
+
+Task #1
+-------
+*Maximum Gap*
+
+Submitted by: Mohammad S Anwar
+
+You are given an array of integers @N.
+
+Write a script to display the maximum difference between two successive
+elements once the array is sorted.
+
+If the array contains only 1 element then display 0.
+
+Example
+
+ Input: @N = (2, 9, 3, 5)
+ Output: 4
+
+ Input: @N = (1, 3, 8, 2, 0)
+ Output: 5
+
+ Input: @N = (5)
+ Output: 0
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2021 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Algorithm
+---------
+Straightforward: Sort the array in ascending order, then iterate through all
+pairs of adjacent elements and record the largest gap. Default to zero if there
+is only one element in the array.
+
+Note on Duplicates
+------------------
+For large arrays containing many duplicate elements, it might be possible to
+obtain a small speed-up by removing duplicates from the sorted array before
+testing adjacent elements. The (optional) flag --unique is provided for this
+purpose. It defaults to False, since for small arrays the speed-up is likely
+more than outweighed by the overhead of duplicate removal.
+
+=end comment
+#==============================================================================
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 106, Task #1: Maximum Gap (Raku)\n".put;
+}
+
+#==============================================================================
+sub MAIN
+(
+ Bool:D :$unique = False, #= (Optional) remove duplicates
+ *@N where { @N.elems > 0 && #= A non-empty, unsorted list
+ .all ~~ Int:D } #= of integers
+)
+#==============================================================================
+{
+ my Int @array = @N.map: { .Int }; # Change IntStrs to Ints
+
+ "Input: \@N = (%s)\n".printf: @array.join: ', ';
+
+ my Int @sorted = @array.sort; # Sort ascending
+ @sorted = @sorted.squish if $unique; # Optionally remove dups
+ my UInt $max-gap = 0;
+
+ # Test every difference between successive elements in the sorted array
+
+ for 1 .. @sorted.end -> UInt $i
+ {
+ my UInt $diff = @sorted[ $i ] - @sorted[ $i - 1 ];
+
+ $max-gap = $diff if $diff > $max-gap;
+ }
+
+ "Output: $max-gap".put;
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s/ ($*PROGRAM-NAME) /raku $0/;
+ $usage.put;
+}
+
+##############################################################################
diff --git a/challenge-106/athanasius/raku/ch-2.raku b/challenge-106/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..c5b31e4c50
--- /dev/null
+++ b/challenge-106/athanasius/raku/ch-2.raku
@@ -0,0 +1,83 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 106
+=========================
+
+*Decimal String*
+
+Submitted by: Mohammad S Anwar
+
+You are given numerator and denominator i.e. $N and $D.
+
+Write a script to convert the fraction into decimal string. If the fractional
+part is recurring then put it in parenthesis.
+
+Example
+
+ Input: $N = 1, $D = 3
+ Output: "0.(3)"
+
+ Input: $N = 1, $D = 2
+ Output: "0.5"
+
+ Input: $N = 5, $D = 66
+ Output: "0.0(75)"
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2021 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Algorithm
+---------
+The Raku Rat class (which does the Rational role) has a mathod base-repeating()
+which returns, separately, the non-repeating part and the repeating part (if
+any) of a given rational number.
+
+=end comment
+#==============================================================================
+
+my UInt constant $BASE = 10;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 106, Task #2: Decimal String (Raku)\n".put;
+}
+
+#==============================================================================
+sub MAIN
+(
+ Int:D $N, #= Numerator (an integer)
+ Int:D $D where { $D != 0 } #= Denominator (a non-zero integer)
+)
+#==============================================================================
+{
+ "Input: \$N = $N, \$D = $D".put;
+
+ my Rat $fraction = Rat.new( $N, $D );
+ my Str ($non-rep, $rep) = $fraction.base-repeating( $BASE );
+
+ qq[Output: "%s%s"\n].printf: $non-rep, $rep ?? "($rep)" !! '';
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s/ ($*PROGRAM-NAME) /raku $0/;
+ $usage.put;
+}
+
+##############################################################################