Perl Weekly Challenge 114
Both of this week’s solutions look remarkably similar, because we were able to utilize the first
subroutine for each one!
Task 1: Next Palindrome Number
You are given a positive integer $N
.
Write a script to find out the next Palindrome Number higher than the given integer $N
.
Example
Input: $N = 1234
Output: 1331
Input: $N = 999
Output: 1001
Solution
See below for explanation and any implementation-specific comments.
sub challenge(Int $N) returns Int {
($N^..Inf).first(-> $num { $num == $num.flip }, :v); # [1][2][3]
}
sub MAIN(Int $N) {
say challenge($N);
}
This program runs as such:
$ raku ch-1.raku 1234
1331
Explanation
This is fairly straightforward; we create an infinite range from $N
to infinity. This range will be lazily evaluated, so we don’t have to worry about memory. Then we find the first instance where $num
is equal to $num.flip
. That’s it!
Specific comments
- Ranges are lazily evaluated, so it is safe to have these seemingly infinite range constructors.
$num.flip
technically returns a string, but==
will coerce it to an integer (sinceeq
should be used for string equality). This is convenient, but also kind of scary that conversions are happening without us knowing.first
returns both the index and value of that index by default. Since we only want the value, we pass in the:v
flag to specify that.
Task 2: Higher Integer Set Bits
You are given a positive integer $N
.
Write a script to find the next higher integer having the same number of 1 bits in binary representation as $N
.
Example
Input: $N = 3
Output: 5
Binary representation of $N is 011. There are two 1 bits. So the next higher integer is 5 having the same the number of 1 bits i.e. 101.
Input: $N = 12
Output: 17
Binary representation of $N is 1100. There are two 1 bits. So the next higher integer is 17 having the same number of 1 bits i.e. 10001.
Solution
See below for explanation and any implementation-specific comments.
sub bits(Int $base-ten) returns Int {
$base-ten.base(2).comb.grep(* eq '1').elems; # [1][2][3][4]
}
sub challenge(Int $N where $N > 0) returns Int {
my $bits = bits($N);
($N^..Inf).first(-> $num { bits($num) == $bits }, :v);
}
sub MAIN(Int $N) {
say challenge($N);
}
This program runs as such:
$ raku ch-2.raku 12
17
Explanation
The meat of this lies in the bits
function. It finds the number of 1
bits for a given integer. Given that, we again construct a range from $N
to infinity and find the first number that has the same number of bits as $N
.
Specific Comments
base
is a cool function to convert a number to any other base. So9.base(3) eq '100'
and255.base(16) eq 'FF'
. We use it to convert base 10 to base 2.- Once we have it in base 2, we need to convert it to a list of digits, so we use
comb
. - Once it has been converted to a list of digits, we filter (
grep
) for digits that equal1
. Sincebase
converted to a string, we use string equality (eq
). - Finally, we just count the elements that equal
1
usingelems
.
Final Thoughts
Lazy evaluation is one of the pillars of functional programming, so it is cool to see it exist in Raku. Always happy when I can break these down into a line or two!