Perl Weekly Challenge: Week 258
Challenge 1:
Count Even Digits Number
You are given a 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
Raku once again comes through with a one-liner.
@*ARGS.grep({$_.chars %% 2}).elems.say
Using the command-line arguments as input, we filter them with .grep()
, finding the length of each one with .chars()
and seeing if it is evenly divisible by two with the %%
operator. Then we count how many we found with .elems()
and output the result with .say()
.
The Perl version is slightly longer because we don't have %%
and have to do an explicit comparison to 0 instead.
say scalar grep {(length $_) % 2 == 0} @ARGV
Challenge 2:
Sum of Values
You are given an array of integers,
@ints
and an integer$k
.Write a script to find the sum of values whose index binary representation has exactly
$k
number of1-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
Raku can do this one (albeit very long) line but I've spread it out to make it more intelligable.
I'm assuming $k
is the first command-line argument and @ints
is all the rest.
We start by getting the indices of each element in @ints
with what has become one of my favorite methods of late, .keys()
.
@ints
.keys
Then each index is converted to binary via .map()
and .base(2)
.map({ $_.base(2) })
Now we can find which indices meet the specs' criterion. We do this with a call to .grep()
which...
.grep({
...splits the index into its' constituent digits with .comb()
,,,
$_
.comb
...finds the digits which are 1's with another .grep()
...
.grep({ $_ == 1 })
... counts how many 1's there were with .elems()
and compares that number to $k
.
.elems == $k
})
Now we know which indices we need, we can find the values of their respective elements by transforming them with .map()
.
We have to prefix 0b
to each index in order for it to be recognized as a binary number literal.
.map({ @ints["0b$_"] })
Then we add up all the values with .sum()
...
.sum
...and print the result.
.say;
Perl works the same way although the visual order of the operations is reversed. And we have to provide our own sum()
function.
say sum(
Unfortunately, it seems that Perl does not allow you to use a binary literal as an array index so it has to first be converted
back into base 10 with the badly named oct()
.
map { $ints[oct "0b$_"] }
grep { scalar (grep { $_ == 1 } (split //, $_)) == $k }
We don't have .base()
either but sprintf('%b')
can do the conversion for us.
map { sprintf '%b', $_ } keys @ints
);