with Raku

This is my response to The Weekly Challenge #268.

You are given two arrays of integers of same size,

Write a script to find the magic number that when added to each elements of one of the array gives the second array. Element order is not important.

Example 1:

`@x`

and `@y`

.
Write a script to find the magic number that when added to each elements of one of the array gives the second array. Element order is not important.

Example 1:

Input: @x = (3, 7, 5)
@y = (9, 5, 7)
Output: 2
The magic number is 2.
@x = (3, 7, 5)
+ 2 2 2
@y = (5, 9, 7)

Example 2:
Input: @x = (1, 2, 1)
@y = (5, 4, 4)
Output: 3
The magic number is 3.
@x = (1, 2, 1)
+ 3 3 3
@y = (5, 4, 4)

Example 3:
Input: @x = (2)
@y = (5)
Output: 3

File: magic-number

#! /usr/bin/env raku
unit sub MAIN ($x, $y, :v(:$verbose)); # [1]
my @x = $x.words>>.Int.sort; # [2]
my @y = $y.words>>.Int.sort; # [2a]
die "Not the same length" unless @x.elems == @y.elems; # [3]
my @pairs = @x Z @y; # [4]
say ":Pairs: { @pairs.raku }" if $verbose;
my @diff = @pairs.map({ $_[0] - $_[1] }); # [5]
say ":Diff: { @diff.join(", ") }" if $verbose;
say ( [==] @diff ) ?? @diff[0].abs !! 'error'; # [6]

[1] The two arrays as space separated strings.

[2] Turn each string into an array of integers. This will blow up on
non-integer input, which is ok. It will also convert non-integer values
to integers, which may be not so ok. Use `.Numeric`

instead, and smart
match the resulting arrays with e.g. `~~ Int`

if that conversion
bothers you. We sort them, as that is the easiest way to ensure that
the differences between the values in the two arrays are optimal.

[3] Ensure that the two arrays have the same length.

[4] Merge (or zip) the arrays together, using the zip operator
`Z`

. The result is a list of Pair objects; one value from each list
(in order).

See docs.raku.org/routine/Z for more information about `Z`

.

[5] Reduce the Pairs to a single value each (with `map`

and a simple
subtraction of the two values), resulting in an array of differences.

[6] Are the differences the same? If so print it (without a sign, if any). If not, print an error message.

Running it:

$ ./magic-number "3 7 5" "9 5 7"
2
$ ./magic-number "1 2 1" "5 4 4"
3
$ ./magic-number 2 5
3

Looking good.

With verbose mode:

$ ./magic-number -v "3 7 5" "9 5 7"
:Pairs: [(3, 5), (5, 7), (7, 9)]
:Diff: -2, -2, -2
2
$ ./magic-number -v "1 2 1" "5 4 4"
:Pairs: [(1, 4), (1, 4), (2, 5)]
:Diff: -3, -3, -3
3
$ ./magic-number -v 2 5
:Pairs: [(2, 5),]
:Diff: -3
3

The challenge and examples does not state what should happen when we do
not have a magic number, but the `!!`

part of [6] handles that:

$ ./magic-number -v "1 2 1" "5 4 42"
:Pairs: [(1, 4), (1, 5), (2, 42)]
:Diff: -3, -4, -40
error

You are given an array of integers,

Write a script to create a new array made up of elements of the given array. Pick the two smallest integers and add it to new array in decreasing order i.e. high to low. Keep doing until the given array is empty.

Example 1:

File: number-game
`@ints`

, with even number of
elements.
Write a script to create a new array made up of elements of the given array. Pick the two smallest integers and add it to new array in decreasing order i.e. high to low. Keep doing until the given array is empty.

Example 1:

Input: @ints = (2, 5, 3, 4)
Output: (3, 2, 5, 4)
Round 1: we picked (2, 3) and push it to the new array (3, 2)
Round 2: we picked the remaining (4, 5) and push it to the new array
(5, 4)

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

Example 3:
Input: @ints = (1, 2, 2, 3)
Output: (2, 1, 3, 2)

#! /usr/bin/env raku
unit sub MAIN (*@ints where @ints.elems > 1 # [1]
&& @ints.elems %% 2 # [1a]
&& all(@ints) ~~ Int, # [1b]
:v(:$verbose));
my @sorted = @ints.sort; # [2]
my @new; # [3]
while @sorted # [4]
{
print ":Sorted: { @sorted.join(",")}" if $verbose;
my $a = @sorted.shift; # [5]
my $b = @sorted.shift; # [6]
say " -> pick $a,$b -> add $b,$a" if $verbose;
@new.append: $b, $a; # [7]
}
say "({ @new.join(", ") })"; # [8]

[1] At least one element, the number of them must be even [1a], and they must all be integers [1b].

[2] Sort them, as that makes it easier to pick the correct (i.e. lowest) values.

[3] The result will end up here.

[4] As long as we have unfinished business.

[5] Get the lowest remaining value.

[6] And the lowest remaining vaule, after the one above.

[7]
Add them to the result, in reverse order. Note the usage of
`append`

so that the values are added *one at a time* to the
result, whereas `push`

would have added a new list (with two items)
to the result.

See docs.raku.org/routine/push for more information about `push`

.

See docs.raku.org/routine/append for more information about `append`

.

[8] Pretty print the result.

Running it:

$ ./number-game 2 5 3 4
(3, 2, 5, 4)
$ ./number-game 9 4 1 3 6 4 6 1
(1, 1, 4, 3, 6, 4, 9, 6)
$ ./number-game 2 1 3 2
(2, 1, 3, 2)

Looking good.

With verbose mode:

$ ./number-game -v 2 5 3 4
:Sorted: 2,3,4,5 -> pick 2,3 -> add 3,2
:Sorted: 4,5 -> pick 4,5 -> add 5,4
(3, 2, 5, 4)
$ ./number-game -v 9 4 1 3 6 4 6 1
:Sorted: 1,1,3,4,4,6,6,9 -> pick 1,1 -> add 1,1
:Sorted: 3,4,4,6,6,9 -> pick 3,4 -> add 4,3
:Sorted: 4,6,6,9 -> pick 4,6 -> add 6,4
:Sorted: 6,9 -> pick 6,9 -> add 9,6
(1, 1, 4, 3, 6, 4, 9, 6)
$ ./number-game -v 2 1 3 2
:Sorted: 1,2,2,3 -> pick 1,2 -> add 2,1
:Sorted: 2,3 -> pick 2,3 -> add 3,2
(2, 1, 3, 2)

And that's it.