Even Sum
with Raku

by Arne Sommer

Even Sum with Raku

[278] Published 1. March 2024.

This is my response to The Weekly Challenge #258.

Challenge #258.1: Count Even Digits Number

You are given an array of positive integers, @ints.

Write a script to find out how many integers have even number of digits.

Example 1:
Input: @ints = (10, 1, 111, 24, 1000)
Output: 3

There are 3 integers having even digits i.e. 10, 24 and 1000.
Example 2:
Input: @ints = (111, 1, 11111)
Output: 0
Example 3:
Input: @ints = (2, 8, 1024, 256)
Output: 1
File: cedn
#! /usr/bin/env raku

subset PosInt of Int where * >= 1;                                     # [1]

unit sub MAIN (*@ints where @ints.elems > 0 && all(@ints) ~~ PosInt);  # [2]

say @ints.grep( *.chars %% 2 ).elems;                                  # [3]

[1] The UInt (Unsigned Int) type includes zero, so we cannot use that. But a suitable custom type with subset does the trick.

See docs.raku.org/language/typesystem#subset for more information about subset.

[2] Ensure at least one element, and they must all be positive integers.

[3] Use grep to retain the values with a character length that is even, i.e. divisible (the %% operator) by 2. Then we print the number of elements we get. And that really is all there is to it...

See docs.raku.org/routine/%% for more information about the Divisibility Operator %%.

Running it:

$ ./cedn 10 1 111 24 1000
3

$ ./cedn 111 1 11111
0

$ ./cedn 2 8 1024 256
1

Looking good.

Challenge #258.2: Sum of Values

You are given an array of integers, @int and an integer $k.

Write a script to find the sum of values whose index binary representation has exactly $k number of 1-bit set.

Example 1:
Input: @ints = (2, 5, 9, 11, 3), $k = 1
Output: 17

Binary representation of index 0 = 0
Binary representation of index 1 = 1
Binary representation of index 2 = 10
Binary representation of index 3 = 11
Binary representation of index 4 = 100

So the indices 1, 2 and 4 have total one 1-bit sets.
Therefore the sum, $ints[1] + $ints[2] + $ints[3] = 17
Example 2:
Input: @ints = (2, 5, 9, 11, 3), $k = 2
Output: 11
Example 3:
Input: @ints = (2, 5, 9, 11, 3), $k = 0
Output: 2
File: sum-of-values
#! /usr/bin/env raku

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

my $output = 0;                                                    # [2]

for ^@ints.elems -> $index                                         # [3]
{
  my $binary = $index.fmt('%b');                                   # [4]
  my $sum    = $binary.comb.sum;                                   # [5]

  if $sum == $k                                                    # [6]
  {
    $output += @ints[$index];                                      # [6a]

    say ":Index $index binary $binary -> $sum match - adding \
      @ints[$index] -> $output" if $verbose;
  }
  elsif $verbose
  {
    say ":Index $index binary $binary -> $sum";
  }
}

say $output;                                                       # [7]

[1] Specify the $k value first, followed by the @ints [1a].

[2] The sum will be accumulated here.

[3] Iterate over the array indices.

[4] Convert the current index to binary with fmt, the method form of the more famous sprintf.

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

[5] The number of 1 bits is just a matter of splitting the string into individual characters (with comb) and adding them (i.e. the zeroes and the ones) all up.

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

[6] Add the current number to the sum [6a], if we got a binary index match.

[7] Print the sum.

Running it, with verbose mode:

$ ./sum-of-values -v 1 2 5 9 11 3
:Index 0 binary 0 -> 0
:Index 1 binary 1 -> 1 match - adding 5 -> 5
:Index 2 binary 10 -> 1 match - adding 9 -> 14
:Index 3 binary 11 -> 2
:Index 4 binary 100 -> 1 match - adding 3 -> 17
17

$ ./sum-of-values -v 2 2 5 9 11 3
:Index 0 binary 0 -> 0
:Index 1 binary 1 -> 1
:Index 2 binary 10 -> 1
:Index 3 binary 11 -> 2 match - adding 11 -> 11
:Index 4 binary 100 -> 1
11

$ ./sum-of-values -v 0 2 5 9 11 3
:Index 0 binary 0 -> 0 match - adding 2 -> 2
:Index 1 binary 1 -> 1
:Index 2 binary 10 -> 1
:Index 3 binary 11 -> 2
:Index 4 binary 100 -> 1
2

Looking good.

And that's it.