# RogerBW's Blog

The Weekly Challenge 182: Max is Common 14 September 2022

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.

1. Posted by Stephen G Lynn at 03:07pm on 14 September 2022

Maybe 'each' in Perl 5.12+ would be the equivalent of Rust enumerate. https://perldoc.perl.org/functions/each

2. Posted by RogerBW at 03:12pm on 14 September 2022

Excellent, thanks! I know that as a function on hashes, and didn't realise it could apply to arrays too.