Two Elements
with Raku

by Arne Sommer

Two Elements with Raku

[281] Published 20. March 2024.

This is my response to The Weekly Challenge #261.

Challenge #261.1: Element Digit Sum

You are given an array of integers, @ints.

Write a script to evaluate the absolute difference between element and digit sum of the given array.

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

Element Sum: 1 + 2 + 3 + 45 = 51
Digit Sum: 1 + 2 + 3 + 4 + 5 = 15
Absolute Difference: | 51 - 15 | = 36
Example 2:
Input: @ints = (1,12,3)
Output: 9

Element Sum: 1 + 12 + 3 = 16
Digit Sum: 1 + 1 + 2 + 3 = 7
Absolute Difference: | 16 - 7 | = 9
Example 3:
Input: @ints = (1,2,3,4)
Output: 0

Element Sum: 1 + 2 + 3 + 4 = 10
Digit Sum: 1 + 2 + 3 + 4 = 10
Absolute Difference: | 10 - 10 | = 0
Example 4:
Input: @ints = (236, 416, 336, 350)
Output: 1296

Negative integers will cause problems. (How would you handle e.g. «-25»? As «-2 + 5 = 3» or as «-(2 + 5) = -7»?) So I have chosen to make them illegal. Zero is ok.

File: element-digit-sum
#! /usr/bin/env raku

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

my $elem-sum  = @ints.sum;                                          # [2]
my $digit-sum = @ints>>.comb>>.sum.sum;                             # [3]

say ": Elem sum: $elem-sum, Digit sum: $digit-sum" if $verbose;

say abs($elem-sum - $digit-sum);                                    # [4]

[1] Unsigned integers, and at least one of them.

[2] Get the sum (with sum).

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

[3] Split each value into separate digits (with >>.comb). The result is a two dimentional list. Then we collapse all the inner lists to a sum for each one (with >>.sum). Then we collapse the remaining list to a single sum (with .sum).

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

[4] Print the absolute value (abs) of the difference between the two values.

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

Running it:

$ ./element-digit-sum 1 2 3 45
36

$ ./element-digit-sum 1 12 3
9

$ ./element-digit-sum 1 2 3 4
0

$ ./element-digit-sum 230 416 336 350
1296

Looking good.

With verbose mode:

$ ./element-digit-sum -v 1 2 3 45
: Elem sum: 51 Digit sum: 15
36

$ ./element-digit-sum -v 1 12 3
: Elem sum: 16, Digit sum: 7
9

$ ./element-digit-sum -v 1 2 3 4
: Elem sum: 10, Digit sum: 10
0

$ ./element-digit-sum -v 230 416 336 350
: Elem sum: 1332, Digit sum: 36
1296

Challenge #261.2: Multiply by Two

You are given an array of integers, @ints and an integer $start.

Write a script to do the following:
  1. Look for $start in the array @ints, if found multiply the number by 2
  2. If not found stop the process otherwise repeat

In the end return the final value.

Example 1:
Input: @ints = (5,3,6,1,12) and $start = 3
Output: 24

Step 1: 3 is in the array so 3 x 2 = 6
Step 2: 6 is in the array so 6 x 2 = 12
Step 3: 12 is in the array so 12 x 2 = 24

24 is not found in the array so return 24.
Example 2:
Input: @ints = (1,2,4,3) and $start = 1
Output: 8

Step 1: 1 is in the array so 1 x 2 = 2
Step 2: 2 is in the array so 2 x 2 = 4
Step 3: 4 is in the array so 4 x 2 = 8

8 is not found in the array so return 8.
Example 3:
Input: @ints = (5,6,7) and $start = 2
Output: 2

2 is not found in the array so return 2.
File: multiply-by-two
#! /usr/bin/env raku

unit sub MAIN (Int $start is copy,                                 # [1]
               *@ints where all(@ints) ~~ Int && @ints.elems > 0,  # [2]
               :v(:$verbose));

my $step = 1;                                                      # [3]

while any(@ints) == $start                                         # [4]
{
  say ": Step { $step++ }: $start is in the array, so $start x 2 = \
    { $start * 2 }" if $verbose;

  $start =  $start * 2;                                            # [5]
}

say ": $start is not found in the array, so return $start" if $verbose;

say $start;                                                        # [6]

[1] Specify the start (integer) value first. The is copy trait enables us to change the value later on (in [4]).

See docs.raku.org/type/Signature#index-entry-trait_is_copy for more information about is copy.

[2] Follow on with the integer array, with at least one element.

[3] Used by verbose mode only.

[4] As long as the current value (called start for fun) is present in the array, which we look up with an any junction.

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

[5] Update the start value.

[6] Print the result.

Running it:

$ ./multiply-by-two 3 5 3 6 1 12
24

$ ./multiply-by-two 1 1 2 4 3
8

$ ./multiply-by-two 2 5 6 7
2

Looking good.

With verbose mode:

$ ./multiply-by-two -v 3 5 3 6 1 12
: Step 1: 3 is in the array, so 3 x 2 = 6
: Step 2: 6 is in the array, so 6 x 2 = 12
: Step 3: 12 is in the array, so 12 x 2 = 24
: 24 is not found in the array, so return 24
24

$ ./multiply-by-two -v 1 1 2 4 3
: Step 1: 1 is in the array, so 1 x 2 = 2
: Step 2: 2 is in the array, so 2 x 2 = 4
: Step 3: 4 is in the array, so 4 x 2 = 8
: 8 is not found in the array, so return 8
8

$ ./multiply-by-two -v 2 5 6 7
: 2 is not found in the array, so return 2
2

And that's it.