Perl Weekly Challenge 134: Pandigital Numbers

by Abigail

Challenge

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

As per the wikipedia, 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.

Discussion

It's clear that the first pandigital numbers are ten digits long, and contain each of the digits exactly once. There are \(9 \cdot 9! = 3265920\) pandigital numbers with exactly ten digits. Those are all the permutations of the digits 0 to 9, excluding the permutations starting with a 0.

Since the pandigital numbers are in order, all the first six pandigital numbers start with 1023456, followed by a permutation of the digits 7, 8, and 9. Since we only need to generate the first five pandigital numbers, the permutations we need are 789, 798, 879, 897, and 978 (and in that order).

Solution

Our solutions will have an array with the five permutations of 7, 8, and 9 we are interested in. This array will be hardcoded — this set is too small and simple to be bothered with an algorithm to generate them.

We will loop over the array, and either print "1023456" and a permutation as a string, or the sum of 1023456000 and a permutation as a number.

AWK

AWK doesn't have array literals, so we start with populating an array with permutations using split:

n = split ("789 798 879 897 978", tails, " ")

This splits the string "789 798 879 897 978" on spaces, with the results placed in the array tails. The return value of split is the number of resulting fields — which is the size of the array tails.

We can now print the numbers:

for (i = 1; i <= n; i ++) {
    print "1023456" tails [i]
}

In AWK, concatenation is done by just putting values next to each other.

Find the full program on GitHub.

Bash

for n in 789 798 879 897 978
do echo 1023456$n
done

In Bash, we don't even have to bother we an array. We can directly loop over a list. Concatenation is done by just sticking $n to 1023456.

Find the full program on GitHub.

Basic

We make use of a very barebones implementation of BASIC: Language::Basic. This means, no array literals. So, when we start off with creating an array, we have to assign each value separately:

100 DIM T(5)
110 T (1) = 789
120 T (2) = 798
130 T (3) = 879
140 T (4) = 897
150 T (5) = 978

Line 100 declares an array T, of size five. The next five lines set the permutations.

We now loop over the array, printing the sum of 1023456000 and the permutation:

200 FOR i = 1 TO 5
210     PRINT 1023456000 + T (i)
220 NEXT i

Find the full program on GitHub.

bc

No array literals in bc either, so again, we have to set each value separately. We don't have to declare the variable though:

t[1] = 789; t[2] = 798; t[3] = 879; t[4] = 897; t[5] = 978

We can now print the sum of 1023456000 and each of the permutations:

for (i = 1; i <= 5; i ++) {
    1023456000 + t[i]
}

Find the full program on GitHub.

Befunge-93

There are no variables in Befunge-93; just the stack, and the 80x24 cells which make up the program. Befunge-93 doesn't have strings either, just unsigned integers.

We start up by putting the wanted permutations on the stack — or rather, the ASCII values of the fifteen characters which make up the five permutations:

"879798978897987"v

Note that we put the last characters first on the stack; this means that after excuting the statements above, the top of the stack starts with 55, 56, 57, 55, 57, 56, etc, which are the ASCII values for 7, 8, 9, 7, 9, 8, etc.

We will now enter a loop: if the stack is empty (or rather, if the top of the stack is 0), we end the program. Otherwise, we put the ASCII values for 6, 5, 4, 3, 2, 0, and 1 on the stack. We then take the first ten items from the stack, and print them as characters. We finish the loop by pushing 5 on the stack twice, adding them (so we get 10 on top of the stack), and printing this as a character. This causes the program to print a newline after each pandigital number.

>,,,,,,,,,,55+,  v
^                :
^"1023456"       _@

Note that we enter the loop on the top right corner, going down.

Find the full program on GitHub.

C

In C, all variables are typed. So we define an array tail as an array of short, since we're dealing with small enough numbers:

# define SIZE 5

short tail [] = {789, 798, 879, 897, 978};

We can now use a simple loop, using printf to print the pandigital numbers:

for (size_t i = 0; i < SIZE; i ++) {
    printf ("1023456%d\n", tail [i]);
}

Find the full program on GitHub.

csh

Just like in Bash, we can directly iterate over a list, without first putting the permutations in an array:

foreach i (789 798 879 897 978)
    echo 1023456$i
end

Find the full program on GitHub.

Erlang

Erlang is a functional language. In Erlang, one typically does not loop over an array; instead, one uses recursion, combined with polymorphism.

We will first define a function pandigital, which takes an array as argument. The array consists of the permutations, and the function will print the pandigital numbers:

pandigital ([])            -> ok;

pandigital ([Head | List]) ->
    io:fwrite ("1023456~w~n", [Head]),
    pandigital (List).

If the function is called with an empty array, the function just returns without further actions. Otherwise, the function is called with a non-empty array, and we have to look at the second definition. The first element of the array will be named Head, while the rest of array is named List. We will print the pandigital number with the permutation Head, and then recurse with List.

We call this function in the following way:

main () ->
    pandigital ([789, 798, 879, 897, 978]).

Find the full program on GitHub.

Go

To iterate over an array in Go, we use for in combination with range. for is Go's only looping construct; range lets it iterate over a slice. We can give it an array literal as argument, so no need for a separate variable:

for _, t := range [] int {789, 798, 879, 897, 978} {
    fmt . Printf ("1023456%d\n", t)
}

Find the full program on GitHub.

Java

First, we create an array of integers:

int [] tails = {789, 798, 879, 897, 978};

We then use a for loop to iterate over the permutations. We add each permutation to 1023456000, and print it:

int [] tails = {789, 798, 879, 897, 978};
for (int i: tails) {
    System . out . println (1023456000 + i);
}

Find the full program on GitHub.

Lua

In Lua, we can directly iterate over a table literal (in Lua, arrays are called tables). We use the function ipairs, which returns the key-values pairs in order:

for _, tail in ipairs ({789, 798, 879, 897, 978}) do
    print (1023456000 + tail)
end

Find the full program on GitHub.

m4

m4 doesn't have arrays. It doesn't have variables either. It just has macros. Macros with can be redefined (in fact, redefining macros in m4 is quite common). And with some creative use of redefining macros, we can simulate arrays:

define(`tail_set',`define(format(``tail[%d]'',`$1'),`1023456$2')')dnl

This defines a macro tail_set, which takes two arguments, $1, and $2. The first acts as an index, the second as an argument. If the macro tail_set gets invoked (say, with arguments 3 and 879), the result is that another macro is defined, one which defines tail[3], to expand to 1023456879.

Next step is a macro which returns value in the simulated array:

define(`tail',`defn(format(``tail[%d]'',`$1'))')dnl

Note the use of defn: if its argument is an existing macro, it exands to that macro, else it expands to nothing.

We can now populate the array:

tail_set(`5',`789')dnl
tail_set(`4',`798')dnl
tail_set(`3',`879')dnl
tail_set(`2',`897')dnl
tail_set(`1',`978')dnl

Note that we put the permutations into the simulate array in reversed order. This is due to the following macro:

define(`run',`tail($1)
ifelse($1,1,,`run(eval($1-1))')')dnl

The macro run takes a single argument ($1). It first expands to tail($1), which is 1023456 followed by the corresponding permutation. We then look at $1, if it equals 1, we're done. Else, we expand it to run($1-1), which is a basic form of recursion.

We can now finally kick off a myriad of expansions:

run(5)dnl

Note the use of dnl after each macro definition. Anything which isn't a macro to be expanded, is copied as-is by m4. Including any newlines following a macro definition. The dnl token prevents this.

Find the full program on GitHub.

Node.js

In Node.js, arrays are objects, with a forEach method. In that method, we print the corresponding pandigital number to the console, leaving us with a one-liner:

[789, 798, 879, 897, 978] . forEach (t => console . log ("1023456" + t))

Find the full program on GitHub.

Pascal

In Pascal, variable definition go into a section var. We can also use this to initialize the variables. All variables are typed, and array elements are of a specific type as well:

var
    tails: array [1 .. 5] of integer = (789, 798, 879, 897, 978);
    i: integer;

Looping is now easy:

for i := 1 to 5 do begin
    writeln (1023456000 + tails [i]);
end

Find the full program on GitHub.

Perl

In Perl, we can directly iterate over a list. Giving us a simple one liner:

say "1023456$_" for qw [789 798 879 897 978];

Find the full program on GitHub.

PHP

First, defining an array with permutations:

$tails = array (789, 798, 879, 897, 978);

Iteration happens with foreach, and PHP does interpolation in the similar way as Perl and the shell:

foreach ($tails as &$tail) {
    echo "1023456$tail\n";
}

Find the full program on GitHub.

Python

In Python, we can directly iterate over a literal list, giving use a very simple program:

for t in [789, 798, 879, 897, 978]:
    print (1023456000 + t)

Find the full program on GitHub.

R

In R, vectors (as arrays are named), can be constructed with the function c():

t <- c (789, 798, 879, 897, 978)

Now, if we add number to a vector, the number is added to each element. So, its easy to get a vector with the pandigital numbers we need:

t <- t + 1023456000

We can directly print a vector use cat, which has the option to specify a separator (space by default):

cat (t, sep = "\n")

We can combine all this, and end up with a one-liner, eliminating an array variable:

cat (c (789, 798, 879, 897, 978) + 1023456000, sep = "\n")

Find the full program on GitHub.

Ruby

Just like Node.js, Ruby has a method on arrays to iterate over the values: each. Which leads to the following one-liner:

[789, 798, 879, 897, 978] . each {|t| puts (1023456000 + t)}

Find the full program on GitHub.

Scheme

Scheme has a unique way of defining an array:

(define t #@1(789 798 879 897 978))

#() is an array literal. The @1 part indicates the first element of the array has index 1.

The looping construct in Scheme is called do:

(do ((i 1 (1+ i)))
    ((> i (array-length t)))
    (format #t "1023456~d\n" (array-ref t i)))

do takes three arguments. First argument is list of initializations; each element of the list consists of a list with three elements:

Here, we have ((i 1 (1+ i))), which means we have just one loop variable, i, whose initial value is 1, and which gets incremented by 1 after each iteration of the loop. ((1+ i)).

The second argument of do is a list of conditions. If any of the conditions is true, the loop is terminated. (This is opposite of loop conditions in languages like C or Perl, where the loop terminates if the condition is false). Here we have just one condition: (> i (array-length t)), which compares the value in i with the size of the array t. The expression is true if i is larger than the array size.

The third argument of do is the body; it gets executed at each iteration of the loop. In this body, we print the pandigital number. format is the function used in Scheme to print formatted text. (array-ref t i) returns the element from t on index i.

Find the full program on GitHub.

Tcl

In Tcl, we use the construct array set to initialize an array. Note that in Tcl, arrays are associative, so we have to provide indices as well:

array set tail {0 789 1 798 2 879 3 897 4 978}

We now have a simple for loop:

for {set i 0} {$i < [array size tail]} {incr i} {
    puts "1023456$tail($i)"
}

Find the full program on GitHub.


Please leave any comments as a GitHub issue.