ETOOBUSY 🚀 minimal blogging for the impatient
PWC204 - Monotonic Array
TL;DR
Here we are with TASK #1 from The Weekly Challenge #204. Enjoy!
The challenge
You are given an array of integers.
Write a script to find out if the given array is Monotonic. Print 1 if it is otherwise 0.
An array is Monotonic if it is either monotone increasing or decreasing.
Monotone increasing: for i <= j , nums[i] <= nums[j] Monotone decreasing: for i <= j , nums[i] >= nums[j]
Example 1
Input: @nums = (1,2,2,3) Output: 1
Example 2
Input: @nums (1,3,2) Output: 0
Example 3
Input: @nums = (6,5,5,4) Output: 1
The questions
No questions asked! (Maybe we could know if there’s any limit to the integers, so that we can understand if big integer support is needed in Perl. But this is looking for trouble).
The solution
I’m almost happy with the following solution, I only suspect that the
map
might be expressed differently and more idiomatically. Overall,
anyway, I think it’s good:
#!/usr/bin/env raku
use v6;
sub MAIN (*@args) { put monotonic-array(@args) ?? 1 !! 0 }
sub monotonic-array (@array) {
([*] @array.rotor(2 => -1).map({[-] $_}).minmax[0, *-1]) >= 0
}
In a nutshell:
- the array elements are taken two by two, with overalaps. This means taking each possible pair of consecutive elements;
- the difference of each pair is calculated
- the minimum and maximum differences are extracted (
minmax
returns a range, so we take the two extremes)
If these two values have different signs… it’s not monotonic. Otherwise it is!
More or less the same goes in Perl, except that to do the check element by element - arguably this is more efficient, because it does not require calculating all the differences if the first elements already allow taking a decision.
#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
say monotonic_array(@ARGV) ? 1 : 0;
sub monotonic_array (@array) {
my $direction = 0;
for my $i (1 .. $#array) {
my $delta = $array[$i] - $array[$i - 1];
return 0 if $direction * $delta < 0;
$direction ||= $delta;
}
return 1;
}
I like this short-circuiting too, so overall I’m happy with the more low-level solution.
Stay safe!