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;

(Full code on Github.)

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;

(Full code on Github.)

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];

(Full code on Github.)

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;

(Full code on Github.)