Perl Weekly Challenge: Week 217

Challenge 1:

Sorted Matrix

You are given a n x n matrix where n >= 2.

Write a script to find 3rd smallest element in the sorted matrix.

Example 1
Input: @matrix = ([3, 1, 2], [5, 2, 4], [0, 1, 3])
Output: 1

The sorted list of the given matrix: 0, 1, 1, 2, 2, 3, 3, 4, 5.
The 3rd smallest of the sorted list is 1.
Example 2
Input: @matrix = ([2, 1], [4, 5])
Output: 4

The sorted list of the given matrix: 1, 2, 4, 5.
The 3rd smallest of the sorted list is 4.
Example 3
Input: @matrix = ([1, 0, 3], [0, 0, 0], [1, 2, 1])
Output: 0

The sorted list of the given matrix: 0, 0, 0, 0, 1, 1, 1, 2, 3.
The 3rd smallest of the sorted list is 0.

This can be solved in Raku as a one-liner. I'm assuming that the matrix is being passed from the command line like this (for example 1,) "3,1,2" "5,2,4" "0,1,3" i.e. each sub array is a separate argument and each element within it is separated by commas.

Then all we need to do is recreate the matrix structure with .map() and .split(), flatten it out with .flat() and sort it in ascending numeric order. Finally, the third element (which will be the third smallest) is picked out and printed.

@*ARGS.map({ .split(/','/) }).flat.sort({ $^a <=> $^b })[2].say

(Full code on Github.)

We can do a one-liner in Perl too. 0+ has to be added to the beginning to prevent a warning about say() being treated as a function.

say 0+(sort { $a <=> $b } map { split /,/ } @ARGV)[2]

(Full code on Github.)

Challenge 2:

Max Number

You are given a list of positive integers.

Write a script to concatenate the integers to form the highest possible value.

Example 1
Input: @list = (1, 23)
Output: 231
Example 2
Input: @list = (10, 3, 2)
Output: 3210
Example 3
Input: @list = (31, 2, 4, 10)
Output: 431210
Example 4
Input: @list = (5, 11, 4, 1, 2)
Output: 542111
Example 5
Input: @list = (1, 10)
Output: 110

Another one liner. All we have to do is sort the arguments in ascending order and concatenate them. The trick is to sort them in string order not numeric even though we are dealing with numbers. Easy right?

@*ARGS.sort({ $^b cmp $^a }).join.say;

This works for examples one to four but gives 101 for example five. Usually you want the longer digit sequence before the shorter one but some times like this, you want the shorter one. I tried a number of methods to try and determine when to use which order but couldn't figure out one which worked reliably. Then I had an idea, what if I just compared both orders? It is useless extra work in most cases but simple enough that it doesn't really affect the run time in any way especially for small input lists like in the examples. So this was my final solution which works properly on all the examples:

@*ARGS.sort({ $^b ~ $^a cmp $^a ~ $^b }).join.say;

(Full code on Github.)

And here it is in Perl:

say join q{}, sort { $b . $a cmp $a . $b } @ARGV;

(Full code on Github.)