aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2025-06-27 22:17:04 +1000
committerPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2025-06-27 22:17:04 +1000
commitc9647c2984b1a78f285f2f808ff4d73a8220e3ab (patch)
tree649fd65a425b0d343212d72a10bea23afcb20aaf
parent9b60d9035df0ef4c2674e87e9b01844523665e13 (diff)
downloadperlweeklychallenge-club-c9647c2984b1a78f285f2f808ff4d73a8220e3ab.tar.gz
perlweeklychallenge-club-c9647c2984b1a78f285f2f808ff4d73a8220e3ab.tar.bz2
perlweeklychallenge-club-c9647c2984b1a78f285f2f808ff4d73a8220e3ab.zip
Perl & Raku solutions to Tasks 1 & 2 for Week 327
-rw-r--r--challenge-327/athanasius/perl/ch-1.pl165
-rw-r--r--challenge-327/athanasius/perl/ch-2.pl196
-rw-r--r--challenge-327/athanasius/raku/ch-1.raku169
-rw-r--r--challenge-327/athanasius/raku/ch-2.raku189
4 files changed, 719 insertions, 0 deletions
diff --git a/challenge-327/athanasius/perl/ch-1.pl b/challenge-327/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..d0f9157d43
--- /dev/null
+++ b/challenge-327/athanasius/perl/ch-1.pl
@@ -0,0 +1,165 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 327
+=========================
+
+TASK #1
+-------
+*Missing Integers*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given an array of n integers.
+
+Write a script to find all the missing integers in the range 1..n in the given
+array.
+
+Example 1
+
+ Input: @ints = (1, 2, 1, 3, 2, 5)
+ Output: (4, 6)
+
+ The given array has 6 elements.
+ So we are looking for integers in the range 1..6 in the given array.
+ The missing integers: (4, 6)
+
+Example 2
+
+ Input: @ints = (1, 1, 1)
+ Output: (2, 3)
+
+Example 3
+
+ Input: @ints = (2, 2, 1)
+ Output: (3)
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. A non-empty list of integers is entered on the command-line.
+
+=cut
+#===============================================================================
+
+use v5.32; # Enables strictures
+use warnings;
+use Const::Fast;
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $USAGE => <<END;
+Usage:
+ perl $0 [<ints> ...]
+ perl $0
+
+ [<ints> ...] A non-empty list of integers
+END
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 327, Task #1: Missing Integers (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] );
+ }
+
+ printf "Input: \@ints = (%s)\n", join ', ', @ints;
+
+ my $missing = find_missing_ints( \@ints );
+
+ printf "Output: (%s)\n", join ', ', @$missing;
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub find_missing_ints
+#-------------------------------------------------------------------------------
+{
+ my ($ints) = @_;
+ my (@missing, %int_set);
+
+ ++$int_set{ $_ } for @$ints;
+
+ for my $i (1 .. scalar @$ints)
+ {
+ push @missing, $i unless exists $int_set{ $i };
+ }
+
+ return \@missing;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $ints_str, $expd_str) = split / \| /x, $line;
+
+ for ($test_name, $ints_str, $expd_str)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @ints = split / \s+ /x, $ints_str;
+ my $missing = find_missing_ints( \@ints );
+ my @expected = split / \s+ /x, $expd_str;
+
+ is_deeply $missing, \@expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1| 1 2 1 3 2 5|4 6
+Example 2| 1 1 1 |2 3
+Example 3| 2 2 1 |3
+None | 1 2 3 4 5 6|
+Negatives|-2 0 3 5 -4 |1 2 4
diff --git a/challenge-327/athanasius/perl/ch-2.pl b/challenge-327/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..15112aef40
--- /dev/null
+++ b/challenge-327/athanasius/perl/ch-2.pl
@@ -0,0 +1,196 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 327
+=========================
+
+TASK #2
+-------
+*MAD*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given an array of distinct integers.
+
+Write a script to find all pairs of elements with minimum absolute difference
+(MAD) of any two elements.
+
+Example 1
+
+ Input: @ints = (4, 1, 2, 3)
+ Output: [1,2], [2,3], [3,4]
+
+ The minimum absolute difference is 1.
+ Pairs with MAD: [1,2], [2,3], [3,4]
+
+Example 2
+
+ Input: @ints = (1, 3, 7, 11, 15)
+ Output: [1,3]
+
+Example 3
+
+ Input: @ints = (1, 5, 3, 8)
+ Output: [1,3], [3,5]
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. A non-empty list of distinct integers is entered on the command-line.
+
+Note
+----
+Since the input integers are distinct, the smallest possible MAD is 1.
+
+=cut
+#===============================================================================
+
+use v5.32; # Enables strictures
+use warnings;
+use Const::Fast;
+use List::Util qw( min );
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $USAGE => <<END;
+Usage:
+ perl $0 [<ints> ...]
+ perl $0
+
+ [<ints> ...] A non-empty list of distinct integers
+END
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 327, Task #2: MAD (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] )
+ }
+
+ distinct( \@ints ) or error( 'The input integers are not distinct' );
+
+ printf "Input: \@ints = (%s)\n", join ', ', @ints;
+
+ my $mad_pairs = find_MAD_pairs( \@ints );
+
+ printf "Output: %s\n",
+ join ', ', map { sprintf '[%d,%d]', @$_ } @$mad_pairs;
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub find_MAD_pairs
+#-------------------------------------------------------------------------------
+{
+ my ($ints) = @_;
+ my @sorted = sort { $a <=> $b } @$ints;
+ my %ab_diff;
+
+ for my $i (0 .. $#sorted - 1)
+ {
+ my $lhs = $sorted[ $i ];
+ my $rhs = $sorted[ $i + 1 ];
+ my $diff = $rhs - $lhs;
+
+ push @{ $ab_diff{ $diff } }, [ $lhs, $rhs ];
+ }
+
+ my $mad = min keys %ab_diff;
+
+ return $ab_diff{ $mad };
+}
+
+#-------------------------------------------------------------------------------
+sub distinct
+#-------------------------------------------------------------------------------
+{
+ my ($ints) = @_;
+ my %count;
+
+ for (@$ints)
+ {
+ return 0 if ++$count{ $_ } > 1;
+ }
+
+ return 1;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $ints_str, @exp_strs) = split / \| /x, $line;
+
+ for ($test_name, $ints_str, @exp_strs)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @ints = split / \s+ /x, $ints_str;
+ my $mad_pairs = find_MAD_pairs( \@ints );
+ my @expected;
+
+ for my $exp_pair (@exp_strs)
+ {
+ push @expected, [ split / \s+ /x, $exp_pair ];
+ }
+
+ is_deeply $mad_pairs, \@expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1|4 1 2 3 |1 2|2 3|3 4
+Example 2|1 3 7 11 15|1 3
+Example 3|1 5 3 8 |1 3|3 5
diff --git a/challenge-327/athanasius/raku/ch-1.raku b/challenge-327/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..06fd543b42
--- /dev/null
+++ b/challenge-327/athanasius/raku/ch-1.raku
@@ -0,0 +1,169 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 327
+=========================
+
+TASK #1
+-------
+*Missing Integers*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given an array of n integers.
+
+Write a script to find all the missing integers in the range 1..n in the given
+array.
+
+Example 1
+
+ Input: @ints = (1, 2, 1, 3, 2, 5)
+ Output: (4, 6)
+
+ The given array has 6 elements.
+ So we are looking for integers in the range 1..6 in the given array.
+ The missing integers: (4, 6)
+
+Example 2
+
+ Input: @ints = (1, 1, 1)
+ Output: (2, 3)
+
+Example 3
+
+ Input: @ints = (2, 2, 1)
+ Output: (3)
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. A non-empty list of integers is entered on the command-line.
+3. If the first integer in the list is negative, it must be preceded by "--" to
+ signal that it is not a command-line flag.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 327, Task #1: Missing Integers (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ #| A non-empty list of integers
+
+ *@ints where { .elems > 0 && .all ~~ Int:D }
+)
+#===============================================================================
+{
+ "Input: \@ints = (%s)\n".printf: @ints.join: ', ';
+
+ my UInt @missing = find-missing-ints( @ints );
+
+ "Output: (%s)\n".printf: @missing.join: ', ';
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub find-missing-ints( List:D[Int:D] $ints --> List:D[UInt:D] )
+#-------------------------------------------------------------------------------
+{
+ my UInt @missing;
+ my Set[Int] $int-set = Set[Int].new: $ints.map: { .Int }; # Int, NOT IntStr
+
+ for 1 .. $ints.elems -> UInt $i
+ {
+ @missing.push: $i if $i ∉ $int-set;
+ }
+
+ return @missing;
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $ints-str, $expd-str) = $line.split: / \| /;
+
+ for $test-name, $ints-str, $expd-str
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my Int @ints = $ints-str.split( / \s+ /, :skip-empty )
+ .map: { .Int };
+ my UInt @missing = find-missing-ints( @ints );
+ my UInt @expected = $expd-str.split( / \s+ /, :skip-empty )
+ .map: { .Int };
+
+ is-deeply @missing, @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| 1 2 1 3 2 5|4 6
+ Example 2| 1 1 1 |2 3
+ Example 3| 2 2 1 |3
+ None | 1 2 3 4 5 6|
+ Negatives|-2 0 3 5 -4 |1 2 4
+ END
+}
+
+################################################################################
diff --git a/challenge-327/athanasius/raku/ch-2.raku b/challenge-327/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..3dfbd89c9d
--- /dev/null
+++ b/challenge-327/athanasius/raku/ch-2.raku
@@ -0,0 +1,189 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 327
+=========================
+
+TASK #2
+-------
+*MAD*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given an array of distinct integers.
+
+Write a script to find all pairs of elements with minimum absolute difference
+(MAD) of any two elements.
+
+Example 1
+
+ Input: @ints = (4, 1, 2, 3)
+ Output: [1,2], [2,3], [3,4]
+
+ The minimum absolute difference is 1.
+ Pairs with MAD: [1,2], [2,3], [3,4]
+
+Example 2
+
+ Input: @ints = (1, 3, 7, 11, 15)
+ Output: [1,3]
+
+Example 3
+
+ Input: @ints = (1, 5, 3, 8)
+ Output: [1,3], [3,5]
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. A non-empty list of distinct integers is entered on the command-line.
+3. If the first integer in the list is negative, it must be preceded by "--" to
+ signal that it is not a command-line flag.
+
+Note
+----
+Since the input integers are distinct, the smallest possible MAD is 1.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+subset IntPair of List where (Int, Int);
+subset Pos of Int where * > 0;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 327, Task #2: MAD (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ #| A non-empty list of distinct integers
+
+ *@ints where { .elems > 0 && .all ~~ Int:D && distinct( @ints ) }
+)
+#===============================================================================
+{
+ "Input: \@ints = (%s)\n".printf: @ints.join: ', ';
+
+ my IntPair @mad-pairs = find-MAD-pairs( @ints );
+
+ "Output: %s\n".printf:
+ @mad-pairs.map( { '[%d,%d]'.sprintf: @$_ } ).join: ', ';
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub find-MAD-pairs( List:D[Int:D] $ints --> List:D[IntPair:D] )
+#-------------------------------------------------------------------------------
+{
+ my Array[IntPair] %ab-diff{Pos};
+
+ my Int @sorted = $ints.sort;
+
+ for 0 .. @sorted.end - 1 -> UInt $i
+ {
+ my Int $lhs = @sorted[ $i ];
+ my Int $rhs = @sorted[ $i + 1 ];
+ my Pos $diff = $rhs - $lhs;
+
+ %ab-diff{ $diff }.push: [ +$lhs, +$rhs ];
+ }
+
+ my Pos $mad = %ab-diff.keys.min;
+
+ return |%ab-diff{ $mad };
+}
+
+#-------------------------------------------------------------------------------
+sub distinct( List:D[Int:D] $ints --> Bool:D )
+#-------------------------------------------------------------------------------
+{
+ my Pos %count{Int};
+
+ for @$ints
+ {
+ return False if ++%count{ $_ } > 1;
+ }
+
+ return True;
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $ints-str, @exp-strs) = $line.split: / \| /;
+
+ for $test-name, $ints-str, @exp-strs
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my Int @ints = $ints-str.split( / \s+ /, :skip-empty )
+ .map: { .Int };
+ my IntPair @mad-pairs = find-MAD-pairs( @ints );
+ my IntPair @expected;
+
+ for @exp-strs -> Str $exp-pair
+ {
+ @expected.push: [ $exp-pair.split( / \s+ /, :skip-empty )
+ .map: { .Int } ];
+ }
+
+ is-deeply @mad-pairs, @expected, $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|4 1 2 3 |1 2|2 3|3 4
+ Example 2|1 3 7 11 15|1 3
+ Example 3|1 5 3 8 |1 3|3 5
+ END
+}
+
+################################################################################