Min or Min
with Raku

by Arne Sommer

Min or Min with Raku

[330] Published 23. February 2025.

This is my response to The Weekly Challenge #309.

Challenge #309.1: Min Gap

You are given an array of integers, @ints, increasing order.

Write a script to return the element before which you find the smallest gap.

Example 1:
Input: @ints = (2, 8, 10, 11, 15)
Output: 11

 8 - 2  => 6
10 - 8  => 2
11 - 10 => 1
15 - 11 => 4

11 is where we found the min gap.
Example 2:
Input: @ints = (1, 5, 6, 7, 14)
Output: 6

 5 - 1 => 4
 6 - 5 => 1
 7 - 6 => 1
14 - 7 => 7

6 and 7 where we found the min gap, so we pick the first instance.
Example 3:
Input: @ints = (8, 20, 25, 28)
Output: 28

 8 - 20 => 14
25 - 20 => 5
28 - 25 => 3

28 is where we found the min gap.
File: min-gap
#! /usr/bin/env raku

unit sub MAIN (*@ints where all(@ints) ~~ Int  # [1]
                       && ( [<] @ints )        # [1a]
		       && @ints.elems > 1,     # [1b]
               :v(:$verbose));

my $left    = @ints.shift;                     # [2]
my $min-gap = Inf;                             # [3]
my $at      = Inf;                             # [4]

while (@ints.elems)                            # [5]
{
  my $right       = @ints.shift;               # [6]
  my $gap         = $right - $left;            # [7]
  my $is-smallest = $gap < $min-gap;           # [8]
     $min-gap     = $gap if $is-smallest;      # [9]
     $at          = $right if $is-smallest;    # [10]

  say ": $right - $left => $gap { $is-smallest ?? "(smallest)" !! ""}"
    if $verbose;

  $left = $right;                              # [11]
}

say $at;                                       # [12]

[1] An array of integers, in ascending order [1a] (courtesy of the Reduction Metaoperator [] in combination with < (a normal «less than»)), and at least two elements [1b].

See docs.raku.org/language/operators#Reduction_metaoperators for more information about the Reduction Metaoperator [].

[2] Get the first value, the left hand one in the upcoming comparisons.

[3] The minimum gap value, starting at the absolute maximum.

[4] The index of the minimum gap value.

[5] As long as we have unfinished business.

[6] Get the next value, the right hand one in the comparisons.

[7] Calculate the gap

[8] Do we have a smaller gap than already registred?

[9] If so, set the new minimum gap value

[10] - and the index.

[11] Prepare for the next iteration of the loop.

[12] Print the index.

Running it:

$ ./min-gap 2 8 10 11 15
11

$ ./min-gap 1 5 6 7 14
6

$ ./min-gap 8 20 25 28
28

Looking good.

With verbose mode:

$ ./min-gap -v 2 8 10 11 15
: 8 - 2 => 6 (smallest)
: 10 - 8 => 2 (smallest)
: 11 - 10 => 1 (smallest)
: 15 - 11 => 4
11

$ ./min-gap -v 1 5 6 7 14
: 5 - 1 => 4 (smallest)
: 6 - 5 => 1 (smallest)
: 7 - 6 => 1
: 14 - 7 => 7
6

$ ./min-gap -v 8 20 25 28
: 20 - 8 => 12 (smallest)
: 25 - 20 => 5 (smallest)
: 28 - 25 => 3 (smallest)
28


Challenge #309.2: Min Diff

You are given an array of integers, @ints.

Write a script to find the minimum difference between any two elements.

Example 1:
Input: @ints = (1, 5, 8, 9)
Output: 1

1, 5 => 5 - 1 => 4
1, 8 => 8 - 1 => 7
1, 9 => 9 - 1 => 8
5, 8 => 8 - 5 => 3
5, 9 => 9 - 5 => 4
8, 9 => 9 - 8 => 1
Example 2:
Input: @ints = (9, 4, 1, 7)
Output: 2

9, 4 => 9 - 4 => 5
9, 1 => 9 - 1 => 8
9, 7 => 9 - 7 => 2
4, 1 => 4 - 1 => 3
4, 7 => 7 - 4 => 3
1, 7 => 7 - 1 => 6

This program is very similar to «min-gap» from the first part.

File: min-diff
#! /usr/bin/env raku

unit sub MAIN (*@ints where all(@ints) ~~ UInt  # [1]
                          && @ints.elems > 1,   # [1a]
               :v(:$verbose));

my @sorted = @ints.sort;                        # [2]

my $left     = @sorted.shift;                   # [3]
my $min-diff = Inf;                             # [4]

while (@sorted.elems)                           # [5]
{
  my $right       = @sorted.shift;              # [6]
  my $diff        = $right - $left;             # [7]
  my $is-smallest = $diff < $min-diff;          # [8]
     $min-diff    = $diff if $is-smallest;      # [9]

  say ": $right - $left => $diff { $is-smallest ?? "(smallest)" !! ""}"
    if $verbose;

  $left = $right;                               # [10]
}

say $min-diff;                                  # [11]

[1] An array of unsigned integers (the UInt type), with at least 1 element.

See docs.raku.org/type/UInt for more information about the UInt type.

[2] Sort the values, as the minimum difference between any given value will always be lowest when compared to the nearest value (value wise). When we sort them, those values will also be nearest index wise.

[3] Get the left hand value.

[4] The minimum difference.

[5] As long as we have unfinished business.

[6] Get the right hand value.

[7] Compute the difference.

[8] Do we have a new smallest difference?

[9] If so, update the difference.

[10] Preparfe for the next iteration.

[11] Print the value, the lowest difference.

Running it:

$ ./min-diff 1 5 8 9
1

$ ./min-diff 9 4 1 7
2

Looking good.

With verbose mode:

$ ./min-diff -v 1 5 8 9
: 5 - 1 => 4 (smallest)
: 8 - 5 => 3 (smallest)
: 9 - 8 => 1 (smallest)
1

$ ./min-diff -v 9 4 1 7
: 4 - 1 => 3 (smallest)
: 7 - 4 => 3
: 9 - 7 => 2 (smallest)
2

And that's it.