Advent Calendar - December 10, 2023

Sunday, Dec 10, 2023| Tags: Perl

Advent Calendar 2023

|   Day 9   |   Day 10   |   Day 11   |

The gift is presented by Stephen G Lynn. Today he is talking about his solution to The Weekly Challenge - 217. This is re-produced for Advent Calendar 2023 from the original post.

Challenge 1 (Sorted Matrix)

We are given a n by n matrix of numbers, and asked to report the third-smallest number in the matrix.

The specification seems to allow arbitrary non-numeric elements too, but since all the test examples are numeric, I will restrict to numeric matrices. PDL is of course the go-to tool for this.

The core subroutine:

sub sorted_matrix {my ($pdl)=@_; $pdl=$pdl->flat->qsort; $pdl(2);}

The flat method flattens the matrix piddle to a vector piddle, qsort sorts the vector in ascending order, then we just return the third element.

Challenge 2 (Max Number)

We are given a list of positive integers of arbitrary lengths, and asked to concatenate them so as to produce the largest possible concatenated number. Thus, given 1 and 23, we would produce 231, not 123.

To solve this, we exploit the fact that Perl can treat the elements interchangeably as numbers or as strings. We first sort the numbers using a routine that puts $b before $a if $b.$a is greater than $a.$b. Thus, we would sort (1,23) as (23,1) because 231 > 123.

The core snippet:

join '', sort { $b.$a <=> $a.$b } @list;

A simpler approach suggests itself as just the straight descending lexical sort {$b cmp $a}. But this fails for example with (1,10), which would be sorted as 10,1 not the desired 1,10.

The comparison function in sort

Let me briefly explain my own understanding of how comparison functions work in sort. The documentation can be a bit cryptic.

The general syntax of sort is:

sort f($a,$b) @list;

Here f($a,$b) is the comparison function. A comparison function can return -1, 0, or 1. Here $a and $b are standard package variables (global variables) that temporarily store two list elements being compared during the sort process.

If f($a,$b) returns -1, $a is placed before $b in the sorted list.

If f($a,$b) returns 1, $a is placed after $b in the sorted list.

If f($a,$b) returns 0, $a and $b would be tied in the sorted list (in any order in the sorted list but adjacent to each other or to other elements that return 0 when compared to either of them).

With the spaceship operator <=>: $x<=>$y returns -1 if $x is less than $y, 1 if $x is greater than $y, and 0 if $x is numerically equal (==) to $y.

So setting f($a,$b) to $a <=> $b will sort in ascending order, while setting f($a,$b) to $b <=> $a will sort in descending order.

With the string comparison operator cmp: $x cmp $y returns -1 if $x is before $y in the dictionary ($x lt $y), 1 if $x is after $y in the dictionary ($x gt $y), and 0 if the value of $x is the same string as the value of $y ($x eq $y).

We could rewrite the core snippet above as follows to make the logic more clear:

sub f {my ($x,$y)=@_; $y.$x <=> $x.$y}
join '', sort &f($a,$b) @list;

If you have any suggestion then please do share with us

|   Advent Calendar 2023   |


If you have any suggestions or ideas then please do share with us.

Contact with me