I’ve been doing the Weekly
Challenges. The
latest
involved list searching and finding a common subpath. (Note that this
is open until 18 September 2022.)
Task 1: Max Index
You are given a list of integers.
Write a script to find the index of the first biggest number in the list.
I interpret "first biggest" to mean the first occurrence of the
largest number. Quite straightforward in most languages: go through
the list, and if the value is higher than any stored value store this
value as maximum and its index for output, then return the last stored
index. For example in Rust:
fn maxindex(n: Vec<isize>) -> usize {
let mut mxv = 0;
let mut mxi = 0;
for (i, v) in n.iter().enumerate() {
if i == 0 || *v > mxv {
mxv = *v;
mxi = i;
}
}
mxi
}
(We'll never actually use the initial values of mxi and mxv unless the
list is empty, and behaviour in that case is undefined. -1
would
probably be a helpful thing to return in that case.)
But what a few languages lack is that enumerate
(in Rust and Python;
each_with_index
in Ruby, .forEach
in JavaScript, and .withIndex
in Kotlin), which lets me go through a list getting both index and
value in a single operation. Lua and PostScript don't have it – though
I've written one for PostScript. Perl is also lacking this, and that
seems like a shame; sure, I can just iterate through indices and
pull the value out of the list, but it's more faff for the programmer
and an extra chance to get things wrong.
(I thought Raku also lacked it, but I was wrong; you can do it with
the .pairs
method.)
Task 2: Common Path
Given a list of absolute Linux file paths, determine the deepest path to the directory that contains all of them.
A common substring is a more usual sort of task, but this seems fairly
straightforward. I break up the input strings into path components,
then iterate one component at a time until I get a mismatch. In Perl:
sub commonpath($p) {
my @pa;
my @pl;
foreach my $sp (@{$p}) {
Break up the input path, and store it and the number of components in it.
my @q = split '/',$sp;
push @pl,scalar @q;
push @pa,\@q;
}
my @out;
Iterating to the number of components of the shortest path…
foreach my $cl (0..min(@pl)-1) {
my $ex = 0;
Get the value of the first input's component.
my $tx = $pa[0][$cl];
Compare it with the rest of the components at that position. (This
compares it with itself too, but that shouldn't be a major
imposition.) If any of the comparisons fails, drop out of the loop. (I
could do a deep exit here with a label, which I'd use if I were just
writing Perl and/or Raku, but that isn't an option in some of the
languages.)
foreach my $pe (@pa) {
if ($pe->[$cl] ne $tx) {
$ex = 1;
last;
}
}
if ($ex) {
last;
}
push @out,$tx;
}
Assemble and return the matching components.
return join('/',@out);
}
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.