The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

#!/usr/bin/env perl
my $copyright = <<'COPYRIGHT';
# Copyright (c) 2021 by Christian Jaeger <copying@christianjaeger.ch>
# This is free software. See the file COPYING.md that came bundled
# with this file.
COPYRIGHT
=pod
TASK #1: Search Matrix
You are given 5x5 matrix filled with integers such that each row is
sorted from left to right and the first integer of each row is greater
than the last integer of the previous row.
Write a script to find a given integer in the matrix using an
efficient search algorithm.
Example
Matrix: [ 1, 2, 3, 5, 7 ]
[ 9, 11, 15, 19, 20 ]
[ 23, 24, 25, 29, 31 ]
[ 32, 33, 39, 40, 42 ]
[ 45, 47, 48, 49, 50 ]
Input: 35
Output: 0 since it is missing in the matrix
Input: 39
Output: 1 as it exists in the matrix
=cut
use strict;
use utf8;
use warnings FATAL => 'uninitialized';
use v5.32.1; # for `<=` chaining
use experimental 'signatures';
my ($mydir, $myname);
BEGIN {
$0 =~ /(.*?)([^\/]+)\z/s or die "?";
($mydir, $myname) = ($1, $2);
}
use lib "$mydir/../../lib";
use FP::Array_sort qw(on);
use FP::Ops qw(the_method real_cmp);
use FP::Optional qw(have);
use Chj::TEST ":all";
# `on(the_method("first"), \&real_cmp)` would work for sorting but
# doesn't for search, as the array that is given as a search key has
# to compare as equal if the search key is within it. (And we don't
# necessarily know which of the arguments is the key, although
# `perhaps_binsearch` might define that.) Thus introduce:
sub overlap_cmp ($a, $b) {
__ 'Compare two arrays of real numbers. Report equality if the
arrays overlap.';
if ( ($a->first <= $b->first <= $a->last)
or ($b->first <= $a->first <= $b->last))
{
0
} else {
$a->first <=> $b->first
}
}
TEST { overlap_cmp [9, 11, 15], [9] } 0;
TEST { overlap_cmp [9, 11, 15], [11] } 0;
TEST { overlap_cmp [9, 11, 15], [15] } 0;
TEST { overlap_cmp [9, 11, 15], [7] } 1;
TEST { overlap_cmp [9, 11, 15], [16] } -1;
TEST { overlap_cmp [9, 11, 15], [14, 15] } 0;
TEST { overlap_cmp [9, 11, 15], [14] } 0;
TEST { overlap_cmp [9, 11, 15], [15, 16] } 0;
TEST { overlap_cmp [15, 16], [9, 11, 15] } 0;
sub as_sorted ($matrix) {
__ 'Take an array of arrays and mark the inner as sorted numbers
and the outer as sorted by the first item of the subarrays';
$matrix->map(sub ($v) { $v->as_sorted_by(\&real_cmp) })
->as_sorted_by(\&overlap_cmp)
}
sub matrix_contains ($matrix, $n) {
my $m = as_sorted $matrix;
if (my ($inner) = $m->perhaps_binsearch([$n])) {
have($inner->perhaps_binsearch($n))
} else {
''
}
}
my $Matrix = [
[1, 2, 3, 5, 7],
[9, 11, 15, 19, 20],
[23, 24, 25, 29, 31],
[32, 33, 39, 40, 42],
[45, 47, 48, 49, 50]
];
# Perl's canonical false value is '', not 0; leave it at that.
TEST { matrix_contains $Matrix, 35 } '';
TEST { matrix_contains $Matrix, 39 } 1;
sub help {
print "Usage: $0 --repl | --test\n";
exit 1
}
&{
@ARGV
? {
"--repl" => sub {
require FP::Repl::Trap;
FP::Repl::repl();
},
"--test" => sub {
run_tests __PACKAGE__;
}
}->{ $ARGV[0] } // \&help
: \&help
};