This is my response to The Weekly Challenge #258.
@ints
.
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
#! /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.
@int
and an integer $k
.
$k
number of 1-bit
set.
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
#! /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.