Diff Peak
with Raku

by Arne Sommer

Diff Peak with Raku

[363] Published 21. September 2025.

This is my response to The Weekly Challenge #339.

Challenge #339.1: Max Diff

You are given an array of integers having four or more elements.

Write a script to find two pairs of numbers from this list (four numbers total) so that the difference between their products is as large as possible.

In the end return the max difference.

With Two pairs (a, b) and (c, d), the product difference is (a * b) - (c * d).

Example 1:
Input: @ints = (5, 9, 3, 4, 6)
Output: 42

Pair 1: (9, 6)
Pair 2: (3, 4)
Product Diff: (9 * 6) - (3 * 4) => 54 - 12 => 42
Example 2:
Input: @ints = (1, -2, 3, -4)
Output: 10

Pair 1: (1, -2)
Pair 2: (3, -4)
Example 3:
Input: @ints = (-3, -1, -2, -4)
Output: 10

Pair 1: (-1, -2)
Pair 2: (-3, -4)
Example 4:
Input: @ints = (10, 2, 0, 5, 1)
Output: 50

Pair 1: (10, 5)
Pair 2: (0, 1)
Example 5:
Input: @ints = (7, 8, 9, 10, 10)
Output: 44

Pair 1: (10, 10)
Pair 2: (7, 8)
File: max-diff
#! /usr/bin/env raku

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

my $max = -Inf;                                                         # [2]

for @ints.combinations(4) -> @comb                                      # [3]
{
  for (@comb.permutations)[0,2,4] -> @perm                              # [4]
  {  
    my $diff = (( @perm[0] * @perm[1] ) - ( @perm[2] * @perm[3] )).abs; # [5]

    print ": (@perm[0] * @perm[1]) - (@perm[2] * @perm[3]) = $diff" if
      $verbose;
  
    if ($diff > $max)                                                   # [6]
    {
      $max = $diff;                                                     # [6a]
      say " (new max)" if $verbose;
    }
    elsif $verbose
    {
      say '';
    }
  }
}
say $max;                                                               # [7]

[1] At least 4 elements, all of which must be integers.

[2] Initialise the max difference, starting off with something that is less than everything else we can find.

[3] Iterate over all four value combinations of the input values with combinations(4).

> say <1 2 3 4 5>.combinations(4);
((1 2 3 4) (1 2 3 5) (1 2 4 5) (1 3 4 5) (2 3 4 5))

See docs.raku.org/routine/combinations for more information about combinations.

[4] We have to shuffle around the values as well, with permutations. But we do not need all the 24 permutations; just three of them is enough - so that we can combine the first value with the other three.

See docs.raku.org/routine/permutations for more information about permutations.

Why [0,2,4] is enough

The internal order of the first and second value, as well as the (internal value of the) third and fourth, does not matter; as a * b is the same as b * a. The two pairs can also be swapped, as the difference is a positive value; |ab - cd| is the same as |cd - ab|.

> say <1 2 3 4>.permutations;
((1 2 3 4) (1 2 4 3) (1 3 2 4) (1 3 4 2) (1 4 2 3) (1 4 3 2) \
 (2 1 3 4) (2 1 4 3) (2 3 1 4) (2 3 4 1) (2 4 1 3) (2 4 3 1) \
 (3 1 2 4) (3 1 4 2) (3 2 1 4) (3 2 4 1) (3 4 1 2) (3 4 2 1) \
 (4 1 2 3) (4 1 3 2) (4 2 1 3) (4 2 3 1) (4 3 1 2) (4 3 2 1))

[5] Get the difference of the current permutation. Note the use of abs to get rid of a negative sign, if any.

See docs.raku.org/routine/abs for more information about abs.

[6] Is the new difference higher than the previously highest one? If so, save the new value [6a].

[7] Print the result.

Running it:

$ ./max-diff 5 9 3 4 6
42

$ ./max-diff 1 -2 3 -4
10

$ ./max-diff -- -3 -1 -2 -4
10

$ ./max-diff 10 2 0 5 1
50

$ ./max-diff 7 8 9 10 10
44

Looking good.

With verbose mode:

$ ./max-diff -v 5 9 3 4 6
: (5 * 9) - (3 * 4) = 33 (new max)
: (5 * 3) - (9 * 4) = 21
: (5 * 4) - (9 * 3) = 7
: (5 * 9) - (3 * 6) = 27
: (5 * 3) - (9 * 6) = 39 (new max)
: (5 * 6) - (9 * 3) = 3
: (5 * 9) - (4 * 6) = 21
: (5 * 4) - (9 * 6) = 34
: (5 * 6) - (9 * 4) = 6
: (5 * 3) - (4 * 6) = 9
: (5 * 4) - (3 * 6) = 2
: (5 * 6) - (3 * 4) = 18
: (9 * 3) - (4 * 6) = 3
: (9 * 4) - (3 * 6) = 18
: (9 * 6) - (3 * 4) = 42 (new max)
42

$ ./max-diff -v 1 -2 3 -4
: (1 * -2) - (3 * -4) = 10 (new max)
: (1 * 3) - (-2 * -4) = 5
: (1 * -4) - (-2 * 3) = 2
10

$ ./max-diff -v -- -3 -1 -2 -4
: (-3 * -1) - (-2 * -4) = 5 (new max)
: (-3 * -2) - (-1 * -4) = 2
: (-3 * -4) - (-1 * -2) = 10 (new max)
10

$ ./max-diff -v 10 2 0 5 1
: (10 * 2) - (0 * 5) = 20 (new max)
: (10 * 0) - (2 * 5) = 10
: (10 * 5) - (2 * 0) = 50 (new max)
: (10 * 2) - (0 * 1) = 20
: (10 * 0) - (2 * 1) = 2
: (10 * 1) - (2 * 0) = 10
: (10 * 2) - (5 * 1) = 15
: (10 * 5) - (2 * 1) = 48
: (10 * 1) - (2 * 5) = 0
: (10 * 0) - (5 * 1) = 5
: (10 * 5) - (0 * 1) = 50
: (10 * 1) - (0 * 5) = 10
: (2 * 0) - (5 * 1) = 5
: (2 * 5) - (0 * 1) = 10
: (2 * 1) - (0 * 5) = 2
50

$ ./max-diff -v 7 8 9 10 10
: (7 * 8) - (9 * 10) = 34 (new max)
: (7 * 9) - (8 * 10) = 17
: (7 * 10) - (8 * 9) = 2
: (7 * 8) - (9 * 10) = 34
: (7 * 9) - (8 * 10) = 17
: (7 * 10) - (8 * 9) = 2
: (7 * 8) - (10 * 10) = 44 (new max)
: (7 * 10) - (8 * 10) = 10
: (7 * 10) - (8 * 10) = 10
: (7 * 9) - (10 * 10) = 37
: (7 * 10) - (9 * 10) = 20
: (7 * 10) - (9 * 10) = 20
: (8 * 9) - (10 * 10) = 28
: (8 * 10) - (9 * 10) = 10
: (8 * 10) - (9 * 10) = 10
44

Challenge #339.2: Peak Point

You are given an array of altitude gain.

Write a script to find the peak point gained.

Example 1:
Input: @gain = (-5, 1, 5, -9, 2)
Output: 1

start: 0
1st change:  0 + (-5) = -5
2nd change: -5 + 1    = -4
3rd change: -4 + 5    = 1
4th change:  1 + (-9) = -8
5th change: -8 + 2    = -6

max(0, -5, -4, 1, -8, -6) = 1
Example 2:
Input: @gain = (10, 10, 10, -25)
Output: 30

start: 0
1st change:  0 + 10    = 10
2nd change: 10 + 10    = 20
3rd change: 20 + 10    = 30
4th change: 30 + (-25) = 5

max(0, 10, 20, 30, 5) = 30
Example 3:
Input: @gain = (3, -4, 2, 5, -6, 1)
Output: 6

start: 0
1st change:  0 + 3    = 3
2nd change:  3 + (-4) = -1
3rd change: -1 + 2    = 1
4th change:  1 + 5    = 6
5th change:  6 + (-6) = 0
6th change:  0 + 1    = 1

max(0, 3, -1, 1, 6, 0, 1) = 6
Example 4:
Input: @gain = (-1, -2, -3, -4)
Output: 0

start: 0
1st change:  0 + (-1) = -1
2nd change: -1 + (-2) = -3
3rd change: -3 + (-3) = -6
4th change: -6 + (-4) = -10

max(0, -1, -3, -6, -10) = 0
Example 5:
Input: @gain = (-10, 15, 5)
Output: 10

start: 0
1st change:   0 + (-10) = -10
2nd change: -10 + 15    = 5
3rd change:   5 + 5     = 10

max(0, -10, 5, 10) = 10

File: peak-point
#! /usr/bin/env raku

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

my $max     = 0;                                                    # [2]
my $current = 0;                                                    # [3]

say ": Start at 0 (new max)" if $verbose;

for @gain -> $change                                                # [4]
{
  print ": $current + $change = { $current + $change }" if $verbose;

  $current += $change;                                              # [5]

  if ($current > $max)                                              # [6]
  {
    say " (new max)" if $verbose;

    $max = $current;                                                # [6a]
  }
  elsif $verbose
  {
    say '';
  }
}

say $max;                                                           # [7]

[1] At least one element, all of which must be integers. Note that the challenge does not specify integer input, but the examples imply it.

[2] The initial maximum, where we start.

[3] The current altitude, updated as we iterate over the gains.

[4] Iterate over the gains.

[5] Add (or subtract) the current gain to the current altitude.

[6] Do we have a new maximum altitude? If so, set is as the new maximum [6a].

[7] Print the result.

Running it:

$ ./peak-point -- -5 1 5 -9 2
1

$ ./peak-point 10 10 10 -25
30

$ ./peak-point 3 -4 2 5 -6 1
6

$ ./peak-point -- -1 -2 -3 -4
0

$ ./peak-point -- -10 15 5
10

Looking good.

With verbose mode:

$ ./peak-point -v -- -5 1 5 -9 2
: Start at 0 (new max)
: 0 + -5 = -5 (new max)
: -5 + 1 = -4 (new max)
: -4 + 5 = 1 (new max)
: 1 + -9 = -8
: -8 + 2 = -6
1

$ ./peak-point -v 10 10 10 -25
: Start at 0 (new max)
: 0 + 10 = 10 (new max)
: 10 + 10 = 20 (new max)
: 20 + 10 = 30 (new max)
: 30 + -25 = 5
30

$ ./peak-point -v 3 -4 2 5 -6 1
: Start at 0 (new max)
: 0 + 3 = 3 (new max)
: 3 + -4 = -1
: -1 + 2 = 1
: 1 + 5 = 6 (new max)
: 6 + -6 = 0
: 0 + 1 = 1
6

$ ./peak-point -v -- -1 -2 -3 -4
: Start at 0 (new max)
: 0 + -1 = -1
: -1 + -2 = -3
: -3 + -3 = -6
: -6 + -4 = -10
0

$ ./peak-point -v -- -10 15 5
: Start at 0 (new max)
: 0 + -10 = -10
: -10 + 15 = 5 (new max)
: 5 + 5 = 10 (new max)
10

And that's it.