Perl Weekly Challenge: Week 72
Challenge 1:
Trailing zeroes
You are given a positive integer $N (<= 10)
.
Write a script to print number of trailing zeroes in $N!
.
Example 1
Input: $N = 10
Output: 2 as $N! = 3628800 has 2 trailing zeroes
Example 2
Input: $N = 7
Output: 1 as $N! = 5040 has 1 trailing zero
Example 3
Input: $N = 4
Output: 0 as $N! = 24 has 0 trailing zero
In Raku this is basically a one liner though my solution has some additional code for validation.
There are several ways we can compute factorials but I chose to use the [*]
reduction metaoperator which multiplies all the elements in a range. The resulting number is matched against a regular expression and the trailing 0's are extracted as a string.
The length of that string is printed out.
(([*] 1 .. $N) ~~ / <(0+)> $ / // q{}).chars.say;
Perl doesn't have all those fancy operators so we calculate the factorial by starting with a base of 1 and repeatedly multiplying
from 2 .. $N
.
my $factorial = 1;
for my $i (2 .. $N) {
$factorial *= $i;
}
Then again the trailing o's are captured in a regex.
$factorial =~ /(0+)$/;
One problem is that if there are no trailing 0's, the capture ($1
) will be undefined so if have to explicitly set it to 0 in that case.
.
say length $1 // 0;
Challenge 2:
Lines Range
You are given a text file name
$file
and range$A
—$B
where$A <= $B
.Write a script to display lines range
$A
and$B
in the given file.Example
Input:
$ cat input.txt
L1
L2
L3
L4
...
...
...
...
L100
$A = 4 and $B = 12
Output:
L4
L5
L6
L7
L8
L9
L10
L11
L12
In Raku this is another one-liner (again minus the validation code.) IO.lines()
returns a "lazy" list of lines which
won't actually exist unless referenced. So it is more efficient than it looks. Because lists are indexed starting from 0, both $A
and $B
have to be decremented by 1 to get the propper range.
.say for $file.IO.lines[$A - 1 .. $B - 1];
Perl once again is more verbose.
We start by setting up a counter for line numbers.
my $linenumber = 0;
This is the standard best practice way to open a file in Perl.
open my $fn, '<', $file or die "$OS_ERROR\n";
Then we read each line in the file. and increment $linenumber
so lines will be numbered starting from 1 instead of 0.
while (my $line = <$fn>) {
$linenumber++;
If the line number is greater than $B
we are at the end of the range so we can stop reading and break out of the loop.
if ($linenumber < $A) {
next;
}
If the line number is less than $A
we haven't reached the beginning of the range so we can skip further processing and go to the next line in the next iteration of the loop.
if ($linenumber > $B) {
last;
}
At this point we must still be in the range so we can print the line.
print $line;
}
Finally, we mustn't forget to close the file handle.
close $fn;