Perl Weekly Challenge 134: Pandigital Numbers and Distinct Term Count

These are some answers for Week 134 of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on October 17, 2021 at 23:59). This blog post offers some solutions to this challenge, please don’t read on if you intend to complete the challenge on your own.

Task 1: Pandigital Numbers

  • Write a script to generate first 5 Pandigital Numbers in base 10.*

As per the https://en.wikipedia.org/wiki/Pandigital_number, it says:

A pandigital number is an integer that in a given base has among 
its significant digits each digit used in the base at least once.

In base 10, a pandigital number ought to have 10 digits. The first (smallest) pandigital numbers will start with the smallest digits upfront, except that the zero cannot be the first first digit, as it would disappear as non significant. So, to get the first pandigital number we need to start with 1, continue with 0 and then proceed the other digits in increasing order, which leads to 1023456789. The next pandigital number will have its two last digits swapped: 1023456798.

Since we need to find the first five pandigital numbers, they will all start with the sequence 1023456, with the three last digits being the permutations of 7, 8, and 9 in the proper increasing order. There are 6 permutations of three distinct digits, so that will be enough to find the first 5 pandigital numbers.

Pandigital Numbers in Raku

Based on the explanations above, we can hard-code the first seven digits as "1023456" and compute the permutations of the last 3 digits:

use v6;

my $start = "1023456";
my @ends = <7 8 9>.permutations[0..4]>>.join("");
say $start ~ $_ for @ends;

This script displays the following output:

raku ./pandigital.raku
1023456789
1023456798
1023456879
1023456897
1023456978

This script is so simple that we can easily turn it to a Raku one-liner:

$ raku -e 'say "1023456" ~ $_ for (7..9).permutations[0..4]>>.join'
1023456789
1023456798
1023456879
1023456897
1023456978

Pandigital Numbers in Perl

Based on the explanations in the task description section above, we can hard code the first seven digits as "1023456" and compute the permutations of the last 3 digits. For this, since we don’t like using external packages for coding challenges, we implement our own recursive permute subroutine.

use strict;
use warnings;
use feature "say";

my @permutations;

sub permute {
    my ($str, @vals) = @_;
    if (scalar @vals == 0) {
        push @permutations, $str;
        return;
    }
    permute("$str" . $vals[$_], @vals[0..$_-1], @vals[$_+1..$#vals]) for 0..$#vals;
}
permute "", 7, 8, 9;
say "1023456" . $_ for @permutations[0..4];

This script displays the following output:

$ perl ./pandigital.pl
1023456789
1023456798
1023456879
1023456897
1023456978

Task 2: Distinct Terms Count

You are given 2 positive numbers, $m and $n.

Write a script to generate multiplication table and display count of distinct terms.

Example 1:

Input: $m = 3, $n = 3
Output:

   x | 1 2 3
   --+------
   1 | 1 2 3
   2 | 2 4 6
   3 | 3 6 9

Distinct Terms: 1, 2, 3, 4, 6, 9
Count: 6

Example 2:

Input: $m = 3, $n = 5
Output:

   x | 1  2  3  4  5
   --+--------------
   1 | 1  2  3  4  5
   2 | 2  4  6  8 10
   3 | 3  6  9 12 15

Distinct Terms: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15
Count: 11

Distinct Terms Count in Raku

There is nothing complex about this task. We need to loop over all values between 1 and $m and all values between 1 and $n, perform the multiplications and properly format the output. In addition, we use a SetHash to store the distinct computed terms, display them and count them.

use v6;

sub multiplication-table (Int $m, Int $n) {
    my SetHash $distinct;
    say "x |", join " ", map {.fmt("%3d")}, 1..$n;
    for 1..$m -> $i {
        my @res = map { $i * $_ }, 1..$n;
        $distinct{$_} = True for @res;
        say "$i |", join " ", map {.fmt("%3d")}, @res;
    }
    say "Distinct terms: ", $distinct.keys.sort.join(" ");
    say "Count: ", $distinct.keys.elems;
}
multiplication-table(7, 5);

This program displays the following output:

$ raku ./distinct-terms.raku
x |  1   2   3   4   5
1 |  1   2   3   4   5
2 |  2   4   6   8  10
3 |  3   6   9  12  15
4 |  4   8  12  16  20
5 |  5  10  15  20  25
6 |  6  12  18  24  30
7 |  7  14  21  28  35
Distinct terms: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 28 30 35
Count: 22

Distinct Terms Count in Perl

This is a port to Perl of the Raku program above. In Perl, we use a hash to store the distinct terms.

#!/usr/bin/perl
use strict;
use warnings;
use feature qw/say/;

sub multiplication_table {
    my ($m, $n) = @_;
    my %distinct;
    say "x |", join " ", map {sprintf "%3d", $_} 1..$n;
    for my $i (1..$m) {
        my @res = map $i * $_, 1..$n;
        $distinct{$_} = 1 for @res;
        say "$i |", join " ", map {sprintf "%3d", $_} @res;
    }
    say "Distinct terms: ", join " ", sort keys %distinct;
    say "Count: ", scalar keys %distinct;
}
multiplication_table(7, 5);

Output:

$ perl ./distinct-terms.pl
x |  1   2   3   4   5
1 |  1   2   3   4   5
2 |  2   4   6   8  10
3 |  3   6   9  12  15
4 |  4   8  12  16  20
5 |  5  10  15  20  25
6 |  6  12  18  24  30
7 |  7  14  21  28  35
Distinct terms: 1 10 12 14 15 16 18 2 20 21 24 25 28 3 30 35 4 5 6 7 8 9
Count: 22

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on October 24, 2021. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.