August 2022 Archives

Perl Weekly Challenge 180: First Unique Character and Trim List

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

Spoiler Alert: This weekly challenge deadline is due in a few of days from now (on Sept. 4, 2022 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: First Unique Character

You are given a string, $s.

Write a script to find out the first unique character in the given string and print its index (0-based).

Example 1

Input: $s = "Perl Weekly Challenge"
Output: 0 as 'P' is the first unique character

Example 2

Input: $s = "Long Live Perl"
Output: 1 as 'o' is the first unique character

First Unique Character in Raku

This is a straight-forward, no-frills solution. I thought that I could write a better (or, at least, simpler) solution using features such as ArrayHash or Hash::Ordered, but this did not seem to simplify the syntax. Similarly, I initially wanted to use the built-in first routine, but it only made things more complicated. So, I ended up with a plain-vanilla solution using a hash (the %h letter histogram) and an array (the @let array) in parallel, and a hand-made loop to look for the first unique letter.

for "Perl Weekly Challenge", "Long Live Perl" -> $test {
    my @let = $test.comb;
    my %h;      # histogram of letters
    %h{$_}++ for @let;
    say "$test: $_" and last if %h{@let[$_]} == 1 for 0..@let.end;
}

This script displays the following output:

$ raku ./first_unique.raku
Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Perl

The good thing of having used a plain-vanilla solution in Raku is that it can be ported directly to Perl (and other languages) with only small changes. We’re using a hash (the %h letter histogram) and an array (the @let array) in parallel, and a hand-made loop to look for the first unique letter.

use strict;
use warnings;
use feature qw/say/;

for my $test ("Perl Weekly Challenge", "Long Live Perl") {
    my @let = split //, $test;
    my %h;
    $h{$_}++ for @let;
    for my $i (0..$#let) {
        say "$test: $i" and last if $h{$let[$i]} == 1;
    }
}

This script displays the following output:

$ perl ./first_unique.pl
Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Other Languages

The following is a series of implementations of the First Unique Character task in 9 guest languages as follows:

  • D
  • Julia
  • Javascript
  • Kotlin
  • Lua
  • Python
  • Ring
  • Ruby
  • Scala

First Unique Character in D

import std.stdio;
import std.array;

void main() {
    string[] tests = [ "Perl Weekly Challenge", "Long Live Perl" ];
    foreach(test; tests) {
        int[string] histo;
        string[] chars = test.split("");
        foreach (ch; chars) {
            histo[ch]++;
        }
        for (int i = 0; i < chars.length; i++) {
            if (histo[chars[i]] == 1) {
                writeln(test, ": ", i);
                break;
            } 
        }
    }
}

Output:

Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Julia

Note, if you did not guess it, that the only function converts a one-letter string into a char. Also remember that Julia arrays start at index 1. The task asks us to provide the 0-based index of the first unique character. This is unnatural in Julia, so we have to subtract 1 from the Julia index to get a 0-based index.

for test in [ "Perl Weekly Challenge", "Long Live Perl" ]
    histo = Dict()
    letters = split(test, "")
    for ch in test
        histo[ch] = if (haskey(histo, ch)) histo[ch]+1 else 1 end
    end
    for i in 1:length(letters)
        if (histo[only(letters[i])] == 1)
            println(test, ": ", i-1)
            break
        end
    end
end

Note that this construct:

histo[ch] = if (haskey(histo, ch)) histo[ch]+1 else 1 end

makes it possible to avoid the stylistically horrible if ... else five-code-line construct.

Output:

$ julia ./first_unique.jl
Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Javascript

let tests = [ "Perl Weekly Challenge", "Long Live Perl" ]
for  (let i = 0; i < tests.length; i++) {
    test = tests[i]
    histo = new Map();
    chars = test.split("")
    chars.forEach( char => {
        histo.set(char, histo.has(char) ? histo.get(char) + 1 : 1)
    })
    for (let i = 0; i < chars.length; i++) {
        if (histo.get(chars[i]) == 1) {
            console.log(test, ": ", i)
            break
        }
    }
}

Output:

Perl Weekly Challenge :  0
Long Live Perl :  1

First Unique Character in Kotlin

fun main() {
    val tests  = arrayOf("Perl Weekly Challenge", "Long Live Perl")
    for (test in tests) {
        var his = mutableMapOf<Char,Int>() // letter histogram
        val chars = test.toCharArray()
        for (ch in chars) {
            his[ch] = if (his.containsKey(ch)) his[ch]!! + 1 else 1
        }
        for (i in 0..chars.size) {
            if (his[chars[i]] == 1) {
                println(test + ": " + i)
                break
            }
        }
    }
}

Output:

Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Lua

for _, test in pairs{"Perl Weekly Challenge", "Long Live Perl"} do
    local histo = {} -- letter histotogram
    for ch in string.gmatch(test, ".") do
        -- histo[ch] = histo[ch] == nil and 1 or histo[ch] + 1
        histo[ch] = (histo[ch] or 0) + 1
    end
    i = 0
    for ch in string.gmatch(test, ".") do
        if histo[ch] == 1 then
            print(test, ": ", i)
            break
        end
        i = i + 1
    end
end

Note that we’re using here the or logical operator:

histo[ch] = (histo[ch] or 0) + 1

to avoid this stylistically horrible code where histo[ch] is repeated no less that four times:

if histo[ch] == nil then
    histo[ch] = 1
else
    histo[ch] = histo[ch] + 1
end

This works because in Lua, the or logical operator doesn’t return a Boolean value, but the value of the first expression if it evaluates to true, and the value of the second one otherwise.

Output:

Perl Weekly Challenge   :   0
Long Live Perl  :   1

First Unique Character in Python

"""Find the first unique character in the given string"""
for test in ["Perl Weekly Challenge", "Long Live Perl"]:
    histo = dict()
    for char in test:
        histo[char] = histo.get(char, 0) + 1
    for i in range(0, len(test)):
        if histo[test[i]] == 1:
            print(test, ": ", i)
            break

Note that using the histo.get(char, 0) expression provides a default 0 value when the key doesn’t exists, thereby avoiding an if ... else construct.

Output:

$ python3 ./first_unique.py
Perl Weekly Challenge :  0
Long Live Perl :  1

First Unique Character in Ring

for test in [ "Perl Weekly Challenge", "Long Live Perl" ]
    histo = []
    for i = 1 to len(test)
        histo[test[i]] = 0 + histo[test[i]] + 1
    next
    for i = 1 to len(test)
        if histo[test[i]] = 1
            see test + ": " + (i-1) + nl
            exit
        ok
    next
next

Note that a 0-based index is unnatural in Ring, so we have to subtract 1 from the looping variable i.

Output:

$ ring ./first_unique.ring
Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Ruby

for test in ["Perl Weekly Challenge", "Long Live Perl"]
    chars = test.split("")
    # with new(0), 0 becomes the default value when a key is absent
    histo = Hash.new(0)
    for char in chars
        histo[char] += 1
    end
    for i in 0..chars.length - 1
        if histo[chars[i]] == 1
            print test, ": ", i, "\n"
            break
        end
    end
end

Here again, using the 0 parameter in the call to the constructor (Hash.new(0)) tells Ruby to return a 0 default value when the key is absent.

Output:

Perl Weekly Challenge: 0
Long Live Perl: 1

First Unique Character in Scala

object firstUnique extends App {
  import scala.collection.mutable.Map
  val tests: List[String] =
    List("Perl Weekly Challenge", "Long Live Perl")
  for (test <- tests) {
    val chars = test.split("")
    var histo: Map[String, Int] = Map()
    for (ch <- chars) {
      if (histo.contains(ch)) {
        histo(ch) = histo(ch) + 1
      } else {
        histo += (ch -> 1)
      }
    }
    var continue = true
    var i = 0
    while (continue) {
      if (histo(chars(i)) == 1) {
        println(test + ": " + i)
        continue = false

      }
      i = i + 1
    }
  }
}

Output:

Perl Weekly Challenge: 0
Long Live Perl: 1

Task 2: Trim List

You are given list of numbers, @n and an integer $i.

Write a script to trim the given list where element is less than or equal to the given integer.

Example 1

Input: @n = (1,4,2,3,5) and $i = 3
Output: (4,5)

Example 2

Input: @n = (9,0,6,2,3,8,5) and $i = 4
Output: (9,6,8,5)

This is quite easy using the built-in grep function in Raku and Perl (or filter in Python or Scala).

Trim List in Raku

Rather than filtering out items which are less than or equal to the input integer, we keep numbers that are larger than the input integer.

for [3, [1,4,2,3,5]], [4, [9,0,6,2,3,8,5]] -> $test {
    my $i = $test[0];
    my @nums = |$test[1];
    say "i = $i; nums = @nums[] => ", grep { $_ > $i }, @nums;
}

This script displays the following output:

$ raku ./trim_list.raku
i = 3; nums = 1 4 2 3 5 => (4 5)
i = 4; nums = 9 0 6 2 3 8 5 => (9 6 8 5)

Trim List in Perl

use strict;
use warnings;
use feature qw/say/;

for my $test ( [3, [1,4,2,3,5]], [4, [9,0,6,2,3,8,5]] ) {
    my $i = $test->[0];
    my @nums = @{$test->[1]};
    say "i = $i, nums = @nums => ", join " ", grep $_ > $i, @nums;
}

This script displays the following output:

$ perl ./trim_list.pl
i = 3, nums = 1 4 2 3 5 => 4 5
i = 4, nums = 9 0 6 2 3 8 5 => 9 6 8 5

Trim List in Other Languages

The following is a series of implementations of the Trim List task in 14 guest languages as follows:

  • in Awk
  • in C
  • in D
  • in Java
  • in JavaScript
  • in Julia
  • in Go
  • in Kotlin
  • in Lua
  • in Pascal
  • in Python
  • in Ring
  • in Ruby
  • in Scala

Trim List in Awk

Contrary to Raku and Perl, awk doesn’t have a grep or filter feature. So we implement a loop over the values and print out those that satisfy the condition. We’ll do that in several other languages. Also note that, since awk is essentially driven by external data, the data is passed by the shell to the awk script. On each line, the first item in the input integer to be compared the other values.

# run for example as:
# echo '3 1 4 2 3 5 
#      4 9 0 6 2 3 85 ' | awk -f trim_list.awk

{ 
    i = $1
    printf "Input = %-18s- i = %d   => result = ", $0, $1
    for (j = 2; j <= NF; j++) {
        if ( $j > i) {
            printf "%d ", $j
        }
    }
    print ""
}

Output:

$ echo '3 1 4 2 3 5
4 9 0 6 2 3 8 5 ' | awk -f trim_list.awk
Input = 3 1 4 2 3 5       - i = 3   => result = 4 5
Input = 4 9 0 6 2 3 8 5   - i = 4   => result = 9 6 8 5

Trim List in C

C doesn’t have a built-in grep or filter feature. So we implement a loop over the values and print out those that satisfy the condition. On each test line, the first item in the input integer to be compared the other values.

#include <stdio.h>
#include <string.h>

int main() {
    const char tests[2][10] = {
            { 3, 1, 4, 2, 3, 5 },
            { 4, 9, 0, 6, 2, 3, 8, 5 }
        };
    for (int j = 0; j <=1; j++) {
        char test[10];
        memcpy(test, tests[j],  sizeof(tests[j]));
        int i = test[0];
        printf("i = %d; nums = ", i);
        /* printing input test array */
        for (char k = 1; k < sizeof(test); k++) {
            printf("%d ", test[k]);
        }
        printf("  =>  ");
        /* printing the result */
        for (char k = 1; k < sizeof(test); k++) {
            if (test[k] > i) {
                printf("%d ", test[k]);
            }
        }
        printf("%s\n", "");
    }
}

Output:

$ ./a.out
i = 3; nums = 1 4 2 3 5 0 0 0 0   =>  4 5
i = 4; nums = 9 0 6 2 3 8 5 0 0   =>  9 6 8 5

Trim List in D

import std.stdio;

void main() {
    int[][][] tests = [[[3], [1,4,2,3,5]], [[4], [9,0,6,2,3,8,5]]];
    foreach(test; tests) {
        int i = test[0][0];
        int[] nums = test[1];
        write(i, " ", nums, "  =>  ");
        for (int j = 0; j < nums.length; j++) {
            if (nums[j] > i) {
                printf("%d ", nums[j]);
            }
        }
    writeln("");
    }
}

Output:

3 [1, 4, 2, 3, 5]  =>  4 5 
4 [9, 0, 6, 2, 3, 8, 5]  =>  9 6 8 5

Trim List in Java

import java.util.Arrays;

public class TrimList {
    private static final int[][][] tests =
        {{{3}, {1,4,2,3,5}}, {{4}, {9,0,6,2,3,8,5}}};
    public static void main(String[] args) {
        for (int j = 0; j < tests.length; j++) {
            int i = tests[j][0][0];
            int[] nums = tests[j][1];
            System.out.printf("i = %d; nums = %s => ", 
                i, Arrays.toString(nums));
            for (int k = 0; k < nums.length; k++) {
                if (nums[k] > i) {
                    System.out.printf("%d ", nums[k]);
                }
            }
        System.out.printf("%s", "\n");
        }
    }
}

Output:

i = 3; nums = [1, 4, 2, 3, 5] => 4 5 
i = 4; nums = [9, 0, 6, 2, 3, 8, 5] => 9 6 8 5

Trim List in JavaScript

tests = [[[3], [1,4,2,3,5]], [[4], [9,0,6,2,3,8,5]]];
for(let j = 0; j < tests.length; j++) {
    let i = tests[j][0][0]
    let nums = tests[j][1]
    process.stdout.write("i= " + i + " nums= " + nums + "  =>  ")
    for (let k = 0; k < nums.length; k++) {
        if ( nums[k] > i) {
            process.stdout.write(nums[k] + " ")
        }
    }
    process.stdout.write("\n")
}

Output:

i= 3 nums= 1,4,2,3,5  =>  4 5 
i= 4 nums= 9,0,6,2,3,8,5  =>  9 6 8 5

Trim List in Julia

In my humble opinion, Julia is the best language used in this blog post after Raku and Perl. Just consider how concise and clear this implementation is, compared to most other languages. And it has very nice functional programming capabilities (e.g. the filter built-in function below with its lambda). In addition, Julia runs fast. Its only drawback in my view is that the error messages emitted by the compiler or the runtime are really not clear (like most languages that compile to Java code).

for test in [[3, [1,4,2,3,5]], [4, [9,0,6,2,3,8,5]]]
    i = test[1]
    nums = test[2]
    println( "i = $i, num = $nums => ", filter((x) -> x > i, nums))
end

Output:

$ julia ./trim_list.jl
i = 3, num = [1, 4, 2, 3, 5]: [4, 5]
i = 4, num = [9, 0, 6, 2, 3, 8, 5]: [9, 6, 8, 5]

Trim List in Go

package main

import "fmt"

func main() {
    tests := [2][2][8]int{{{3}, {1, 4, 2, 3, 5}}, 
                          {{4}, {9, 0, 6, 2, 3, 8, 5}}
                         }
    for j := 0; j < len(tests); j++ {
        i := tests[j][0][0]
        fmt.Printf("i = %d; nums = ", i)
        nums := tests[j][1]
        fmt.Print(nums, "; => ")
        for k := 0; k < len(nums); k++ {
            if nums[k] > i {
                fmt.Printf("%d ", nums[k])
            }
        }
        fmt.Println("")
    }
}

Output:

i = 3; nums = [1 4 2 3 5 0 0 0]; => 4 5 
i = 4; nums = [9 0 6 2 3 8 5 0]; => 9 6 8 5

Trim List in Kotlin

Declaring a multidimensional array in Kotlin is a pain in the neck (as well as in Scala, and it is even worse in Nim). Besides that, the implementation is quite straight forward.

import java.util.Arrays

fun main() {
    val tests  = arrayOf(arrayOf(intArrayOf(3,), 
                                 intArrayOf(1,4,2,3,5)),
                         arrayOf(intArrayOf(4,), 
                                 intArrayOf(9,0,6,2,3,8,5))
                        )

    for (test in tests) {
        print(Arrays.deepToString(test) + "  =>  ")
        var i = test[0][0]
        var nums = test[1];
        for (j in nums) {
            if (j > i) {
                print(j.toString() + " ")
            }
        }
        println("")

    }
}

Output:

[[3], [1, 4, 2, 3, 5]]  =>  4 5 
[[4], [9, 0, 6, 2, 3, 8, 5]]  =>  9 6 8 5

Trim List in Lua

tests = {{{3}, {1,4,2,3,5}}, {{4}, {9,0,6,2,3,8,5}}}
for _, test in ipairs(tests) do
    local i = test[1][1]
    local nums = test[2]
    io.write("i= ", i, "; nums= ", table.concat(nums, " "), " => ")
    for _, j in ipairs(nums) do
        if j > i then
            io.write(j, " ")
        end
    end
    print("")
end

Output:

i= 3; nums= 1 4 2 3 5 => 4 5 
i= 4; nums= 9 0 6 2 3 8 5 => 9 6 8 5

Trim List in Pascal

In Pascal, since I declared the third dimension of the tests array to be 0..6, I had to fill the empty slots with zeroes. If there is a better way, I do not know it (I learned and used Pascal about 33 years ago and almost did not use it since, please forgive my ignorance). It not, then it is a major weakness of the language. Otherwise, the syntax is a bit verbose, but very clear.

program TrimList;

const tests : array[0..1,0..1,0..6] of integer =
    (((3,0,0,0,0,0,0), (1,4,2,3,5,0,0)), ((4,0,0,0,0,0,0), (9,0,6,2,3,8,5)));

var
    i, j, k: integer;
    nums: array of integer;

begin
    for j := 0 to length(tests) - 1 do
    begin
        i := tests[j][0][0];
        write('i = ', i, '; nums = ');
        nums := tests[j][1];
        for k := 0 to length(nums) - 1 do
        begin
            write(nums[k], ' ');
        end;
        write(' => ');
        for k := 0 to length(nums) - 1 do
        begin
            if nums[k] > i then
                write(nums[k], ' ');
        end;
        writeln('')
    end;
end.

Output:

i = 3; nums = 1 4 2 3 5 0 0  => 4 5 
i = 4; nums = 9 0 6 2 3 8 5  => 9 6 8 5

Trim List in Python

About 19 years ago, I took up Perl and stopped writing in Python (my favorite language for a few years at that point), because I felt Perl was superior. I still think so, but I must admit Python is fairly expressive and concise.

for test in [3, [1,4,2,3,5]], [4, [9,0,6,2,3,8,5]]:
  i = test[0]
  nums = test[1]
  print(i, nums, " => ", list(filter(lambda n: n>i, nums)))

Output:

$ python3 ./trim_list.py
3 [1, 4, 2, 3, 5]  =>  [4, 5]
4 [9, 0, 6, 2, 3, 8, 5]  =>  [9, 6, 8, 5]

Trim List in Ring

for test in [[3, [1,4,2,3,5]], [4, [9,0,6,2,3,8,5]]]
    i = test[1]
    nums = test[2]
    see "i = " + i + " ; nums = " 
    for j in nums
        see "" + j + " "
    next
    see " => "
    for j in nums
        if j > i
            see "" + j + " "
        ok
    next
    see " " +nl
next

Output:

$ ring  ./trim_list.ring
i = 3 ; nums = 1 4 2 3 5  => 4 5
i = 4 ; nums = 9 0 6 2 3 8 5  => 9 6 8 5

Trim List in Ruby

for test in [ [3, [1,4,2,3,5]], [4, [9,0,6,2,3,8,5]] ]
    i = test[0]
    nums = test[1]
    print "i = #{i}, nums = #{nums} => ", nums.select {|n| n > i}
    puts " "
end

Output:

i = 3, nums = [1, 4, 2, 3, 5] => [4, 5] 
i = 4, nums = [9, 0, 6, 2, 3, 8, 5] => [9, 6, 8, 5]

Trim List in Scala

As I said above, declaring multidimensional arrays is a pain in the neck in Scala. And its typing system can be a straitjacket. It’s a pity because Scala has very nice features in terms of combining object-oriented and functional programming paradigms.

object trimList extends App {
  val tests: List[List[List[Int]]] = List(
    List(List(3), List(1, 4, 2, 3, 5)),
    List(List(4), List(9, 0, 6, 2, 3, 8, 5))
  )
  for (test <- tests) {
    val i = test(0)(0)
    val nums = test(1)
    print(s"i: $i, nums: " + nums.mkString(" "))
    println(" => " + nums.filter(_ > i).mkString(" "))
  }
}

Output:

i: 3, nums: 1 4 2 3 5 => 4 5
i: 4, nums: 9 0 6 2 3 8 5 => 9 6 8 5

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 September 11, 2022. And, please, also spread the word about the Perl Weekly Challenge if you can.

Perl Weekly Challenge 179: Ordinal Numbers and Unicode Sparkline

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

Spoiler Alert: This weekly challenge deadline is due in a few of days from now (on Aug. 28, 2022 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: Ordinal Number Spelling

You are given a positive number, $n.

Write a script to spell the ordinal number.

For example,

11 => eleventh
62 => sixty-second
99 => ninety-ninth

Hum, this task is not very interesting, since it has more to do with English than with computer science. I’m not going to enumerate dozens of numeral or ordinal English names. So, contrary to what I usually do, I’ll use an off-the-shelf module to complete this task.

Ordinal Number Spelling in Raku

Here, we use the Lingua::EN::Numbers Raku module:

use Lingua::EN::Numbers;

for 11, 62, 99 -> $num {
    say "$num => ", ordinal($num);
}

This program displays the following output:

$ raku ./ordinal_numbers.raku
11 => eleventh
62 => sixty-second
99 => ninety-ninth

Ordinal Number Spelling in Perl

The Perl module we’re going to use is also called Lingua::EN::Numbers, but it’s not the same package as the Raku module used above.

use strict;
use warnings;
use feature qw/say/;

use Lingua::EN::Numbers qw/num2en_ordinal/;

for my $num (11, 62, 99) {
    say "$num => ", ordinal($num);
}

This program displays the following output:

$ perl ./ordinal_numbers.pl
11 => eleventh
62 => sixty-second
99 => ninety-ninth

Task 2: Unicode Sparkline

You are given a list of positive numbers, @n.

Write a script to print sparkline in Unicode for the given list of numbers.

Here, I regret to have to say that my friend Mohammad has been a bit sloppy, since he did not explain anything about sparklines (I had never heard about sparklines before). A sparkline is a very small graph of successive values laid out horizontally where the height of the line is proportional to the values in succession. See this Wikipedia Page for additional information.

The Rosetta Code Web site provides additional information about Unicode sparklines:

Use the following series of Unicode characters to create a program that takes a series of numbers separated by one or more whitespace or comma characters and generates a sparkline-type bar graph of the values on a single line of output.

The eight characters: ‘▁▂▃▄▅▆▇█’ (Unicode values U+2581 through U+2588).

We have eight Unicode characters of growing size, so the problem essentially boils down to scaling the input sequence to eight steps.

Unicode Sparkline in Raku

my @bars = map {.chr}, 0x2581 .. 0x2588;
for < 2 4 6 8 10 12 10 8 6 4 2>, <0 1 19 20>, 
    <0 999 4000 4999 7000 7999> -> @test {
    my ($min, $max) = @test.minmax[0,*-1];
    say "@test[]; min: $min; max: $max.";
    say join '', @bars[ map { @bars * ($_ - $min) / ($max - $min) min @bars.end }, @test], "\n";
}

This program displays the following output:

$ raku ./sparkline.raku
2 4 6 8 10 12 10 8 6 4 2; min: 2; max: 12.
▁▂▄▅▇█▇▅▄▂▁

0 1 19 20; min: 0; max: 20.
▁▁██

0 999 4000 4999 7000 7999; min: 0; max: 7999.
▁▁▅▅██

Unicode Sparkline in Perl

use strict;
use warnings;
use feature qw/say/;

binmode(STDOUT, ":utf8");
my @bars = map chr, 0x2581 .. 0x2588;

for my $test ([< 2 4 6 8 10 12 10 8 6 4 2>], 
    [<0 1 19 20>], [<0 999 4000 4999 7000 7999>]) {
    my @test = @$test;
    my ($min, $max) = (sort {$a <=> $b} @$test)[0, $#test];
    my $out = "";
    for my $item (@test) {
        my $h = @bars * ($item - $min) / ($max - $min);
        $h = $#bars if $h > $#bars;
        $out .= $bars[int($h)];
    }
    say "@test; min: $min; max: $max.";
    say $out, "\n";
}

This program displays the following output:

$ perl sparkline.pl
2 4 6 8 10 12 10 8 6 4 2; min: 2; max: 12.
▁▂▄▅▇█▇▅▄▂▁

0 1 19 20; min: 0; max: 20.
▁▁██

0 999 4000 4999 7000 7999; min: 0; max: 7999.
▁▁▅▅██

Unicode Sparkline in Julia

function sparkline(test)
    bars = '\u2581':'\u2588'
    bar_count = length(bars)
    min, max = extrema(test)
    out = ""
    for item in test
        h = 1 + bar_count * (item - min) / (max - min)
        h > bar_count && (h = bar_count)
        out = out * string(bars[Int(floor(h))])
    end
    return out * "\n"
end

tests = [ [2, 4, 6, 8, 10, 12, 10, 8, 6, 4, 2],
    [0, 1, 19, 20], [0, 999, 4000, 4999, 7000, 7999] ]
for test in tests
    println(test, "\n")
    println( sparkline(test))
end

Output:

$ julia ./sparkline.jl
[2, 4, 6, 8, 10, 12, 10, 8, 6, 4, 2]

▁▂▄▅▇█▇▅▄▂▁

[0, 1, 19, 20]

▁▁██

[0, 999, 4000, 4999, 7000, 7999]

▁▁▅▅██

Unicode Sparkline in Python

def sparkline(test):
  bars = [chr(bar) for bar in range(9601, 9608+1)]
  minim = min(test)
  maxim = max(test)
  scale = maxim - minim
  length = len(bars)
  line = ""
  for item in test:
    line += bars[min(int((item-minim) / scale * length), length - 1)]
  return line

tests = [ [2, 4, 6, 8, 10, 12, 10, 8, 6, 4, 2], \
  [0, 1, 19, 20], [0, 999, 4000, 4999, 7000, 7999] ]

for test in tests:
  print(test)
  print(sparkline(test), "\n")

Output:

$ python3 sparkline.py
[2, 4, 6, 8, 10, 12, 10, 8, 6, 4, 2]
▁▂▄▅▇█▇▅▄▂▁

[0, 1, 19, 20]
▁▁██

[0, 999, 4000, 4999, 7000, 7999]
▁▁▅▅██

Unicode Sparkline in Ruby

bars = ('▁'..'█').to_a 
tests = [ [1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1],
    [0, 1, 19, 20], [0, 999, 4000, 4999, 7000, 7999] ]
for test in tests
    min, max = test.minmax
    puts test.join(" ")
    puts "min: %.2f; max: %.2f"% [min, max]
    scale = (max - min) / (bars.size - 1)
    line = ""
    for item in test
        h = bars.size * (item - min) / (max - min)
        if h >= bars.size
            h = bars.size - 1
        end
        line += bars[h]
    end
    puts line
    puts " "
end

Output:

1 2 3 4 5 6 7 8 7 6 5 4 3 2 1
min: 1.00; max: 8.00
▁▂▃▄▅▆▇█▇▆▅▄▃▂▁

0 1 19 20
min: 0.00; max: 20.00
▁▁██

0 999 4000 4999 7000 7999
min: 0.00; max: 7999.00
▁▁▅▅██

Unicode Sparkline in Scala

object sparkLine extends App {

  def sparkline(test: Array[Int]): String = {
    val bars = ('\u2581' to '\u2588')
    var outl = ""
    for (item <- test) {
      var h = bars.length * (item - test.min) / (test.max - test.min)
      if (h >= bars.length) { h = bars.length - 1 }
      outl = outl + bars(h)
    }
    return outl
  }
  val tests = Array(
    Array(1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1),
    Array(0, 1, 19, 20),
    Array(0, 999, 4000, 4999, 7000, 7999)
  )
  for (test <- tests) {
    println(test.mkString(" "))
    println("")
    println(sparkline(test))
    println("")
  }
}

Output:

1 2 3 4 5 6 7 8 7 6 5 4 3 2 1

▁▂▃▄▅▆▇█▇▆▅▄▃▂▁

0 1 19 20

▁▁██

0 999 4000 4999 7000 7999

▁▁▅▅██

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 September 4, 2022. And, please, also spread the word about the Perl Weekly Challenge if you can.

Perl Weekly Challenge 177: Damm Algorithm and Palindromic Prime Cyclops

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

Spoiler Alert: This weekly challenge deadline is due in a few of days from now (on Aug. 14, 2022 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: Damm Algorithm

You are given a positive number, $n.

Write a script to validate the given number against the included check digit.

Please checkout the wikipedia page for information.

Example 1

Input: $n = 5724
Output: 1 as it is valid number

Example 2

Input: $n = 5727
Output: 0 as it is invalid number

The algorithm is a check digit algorithm named after H. Michael Damm, who presented it in 2004.

The process is quite simple. We’ll use the quasi-group table provided in the afore-mentioned Wikipedia article:

0 3 1 7 5 9 8 6 4 2
7 0 9 2 1 5 4 8 6 3
4 2 0 6 8 7 1 3 5 9
1 7 5 0 9 8 3 4 2 6
6 1 2 3 0 4 5 9 7 8
3 6 7 4 2 0 9 5 8 1
5 8 6 9 7 2 0 1 3 4
8 9 4 5 3 6 2 0 1 7
9 4 3 8 6 1 7 2 0 5
2 5 8 1 4 3 6 7 9 0

Damm Algorithm in Raku

The process is simple. We start with a temporary value of 0. For each digit in the input number, we look up the table with the temporary variable and the digit, and set the temporary variable to the integer found in the table. At the end, the number is valid is the temporary variable is 0. For our test, we will use the two examples provided in the task specification, and we will test all numbers in the 5700..5800 range.

my @damm =  < 0 3 1 7 5 9 8 6 4 2 >,
            < 7 0 9 2 1 5 4 8 6 3 >,
            < 4 2 0 6 8 7 1 3 5 9 >,
            < 1 7 5 0 9 8 3 4 2 6 >,
            < 6 1 2 3 0 4 5 9 7 8 >,
            < 3 6 7 4 2 0 9 5 8 1 >,
            < 5 8 6 9 7 2 0 1 3 4 >,
            < 8 9 4 5 3 6 2 0 1 7 >,
            < 9 4 3 8 6 1 7 2 0 5 >,
            < 2 5 8 1 4 3 6 7 9 0 >;

sub is-valid ($n) {
    my $t = 0;
    $t = @damm[$t][$_] for $n.comb;
    return $t == 0;
}

for 5724, 5727 -> $test {
    say $test, is-valid($test) ?? " is valid." !! " is not valid.";
}
say "\nValid numbers between 5700 and 5800 are: ";
for 5700..5800 -> $i {
    print "$i " if is-valid $i;
}
say "";

This program displays the following output:

$ raku ./damm-algo.raku
5724 is valid.
5727 is not valid.

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Perl

The algorithm for finding the check digit is the same as the one for testing whether a number is valid. So, rather than simply testing the validity directly as we did in Raku, we’ll write a find_check subroutine to find the check digit. Then, a number will be valid if its check digit is 0. Thus, we sort of get the two functions for the price of one. Besides that, the process is essentially the same as in Raku. Check the Raku section above is you need further explanations.

use strict;
use warnings;
use feature qw/say/;

my @damm =  (
[ < 0 3 1 7 5 9 8 6 4 2 > ],
[ < 7 0 9 2 1 5 4 8 6 3 > ],
[ < 4 2 0 6 8 7 1 3 5 9 > ],
[ < 1 7 5 0 9 8 3 4 2 6 > ],
[ < 6 1 2 3 0 4 5 9 7 8 > ],
[ < 3 6 7 4 2 0 9 5 8 1 > ],
[ < 5 8 6 9 7 2 0 1 3 4 > ],
[ < 8 9 4 5 3 6 2 0 1 7 > ],
[ < 9 4 3 8 6 1 7 2 0 5 > ],
[ < 2 5 8 1 4 3 6 7 9 0 > ] );

sub find_check {
    my $n = shift;
    my $t = 0;
    $t = $damm[$t][$_] for split //, $n;
    return $t;
}

sub is_valid {
    my $n = shift;
    return find_check($n) == 0;
}

for my $test (5724, 5727) {
    say $test, is_valid($test) ? " is valid." : " is not valid.";
}
say "\nValid numbers between 5700 and 5800 are: ";
for my $i (5700..5800) {
    print "$i " if is_valid $i;
}
say "";

This program displays the following output:

$ perl  ./damm-algo.pl
5724 is valid.
5727 is not valid.

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Other Languages

We now present the same Damm algorithm in the following 18 guest languages (in alphabetic order):

  • awk
  • C
  • D
  • Dart
  • Go
  • Java
  • JavaScript
  • Julia
  • Kotlin
  • Lua
  • Nim
  • Pascal
  • Python
  • Ring
  • Ruby
  • Rust
  • Scala
  • Tcl

From now on, for all guest language implementations, the test will consist in listing the valid numbers between 5700 and 5800, a range that includes the two test cases (5724 and 5727) suggested in the task specification.

Damm Algorithm in awk

The awk programming language has minimal support for arrays. It doesn’t seem to support two-dimensional arrays, and iniitializing arrays in a pain in the neck (there may be some way, but the documentation is scarce). So we implement the damm lookup array as an array of strings and initialize it by initializing each item in the array (in the populate_damm function). Then we use the substr built-in function to retrieve the wanted value from the strings.

function is_valid(n) {
    t = 0
    for (j = 1; j <= length(n); j++) {
        t = substr(damm[t],substr(n, j, 1) + 1 ,1)
    }
    return t == 0
}
function populate_damm() {
    damm[0] = "0317598642"
    damm[1] = "7092154863"
    damm[2] = "4206871359"
    damm[3] = "1750983426"
    damm[4] = "6123045978"
    damm[5] = "3674209581"
    damm[6] = "5869720134"
    damm[7] = "8945362017"
    damm[8] = "9438617205"
    damm[9] = "2581436790"
}
BEGIN {
    populate_damm()
    print("Valid numbers between 5700 and 5800 are: ")
    for (i  = 5700; i<= 5800; i++) {
        if (is_valid(i)) {
            printf("%d ", i)
        }
    }
}

Output:

$ awk -f ./damm-algo.awk
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Note that I was thinking about a bc implementation of the Damm algorithm, but I gave up the idea because the situation with arrays (and also documentation) is worse that in awk.

Damm Algorithm in C

Not much to say, the code is quite clear. Just note that, in the temp = damm[temp][str[i] - '0']; code line, we need to subtract the Ascii value of 0 (48) from the value in the str integer-to-string conversion in order to get proper subscripts. We will have to do the same in a number of other guest language implementations.

#include <stdio.h>

const char damm[10][10] = {
        {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
        {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
        {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
        {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
        {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
        {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
        {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
        {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
        {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
        {2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
    };

int is_valid(int num) {
    int temp = 0;
    char str[10];
    int len = sprintf(str, "%d", num);   // convert input int to string
    str[len] = '\0';
    for (int i = 0; i < len; i++) {
         temp = damm[temp][str[i] - '0'];
    }
    return temp == 0;
}

int main() {
    printf("%s\n", "Valid numbers between 5700 and 5800 are: ");
    for (int i = 5700; i < 5800; i++) {
        if (is_valid(i)) 
            printf("%d ", i);
    }
    printf("%s\n", "");
}

Output:

$ ./a.out
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in D

As usual, the D syntax is very similar to the C syntax, but D is just a bit simpler to use than C.

import std.stdio;
import std.conv;

auto damm = [
    [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
    [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
    [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
    [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
    [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
    [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
    [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
    [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
    [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
    [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
];

bool is_valid (int num) {
    string str = to!string(num, 10);
    int temp = 0;
    foreach (ch; str) {
        temp = damm[temp][ch - '0'];
    }
    return temp == 0;
}

void main() {
    writeln("Valid numbers between 5700 and 5800 are: ");
    for (int i = 5700; i < 5800; i++) {
        if (is_valid(i)) 
            printf("%d ", i);
    }
    writeln("");
}

Output:

Valid numbers between 5700 and 5800 are: 
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Dart

Like in awk, I haven’t found a good way to declare and initialize two-dimensional arrays in Dart, and the documentation is quite sparse. So I used the same solution as in awk: an array of strings.

import "dart:io";

var damm = [ "0317598642",
             "7092154863",
             "4206871359",
             "1750983426",
             "6123045978",
             "3674209581",
             "5869720134",
             "8945362017",
             "9438617205",
             "2581436790" ];

void main() {
    print("Valid numbers between 5700 and 5800 are:");
    for (int i = 5700; i <= 5800; i++ ) {
        if (is_valid(i)) {
            stdout.write("$i ");
        }
    }
    stdout.write("\n");
}
bool is_valid(n) {
    var digits = n.toString().split("");
    int temp = 0;
    var len = digits.length;
    for (int i = 0; i < len; i++) { 
        var row = damm[temp];
        var idx = int.parse(digits[i]);
        temp = int.parse(row[idx]);
    }
    return temp == 0;
}

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Go

import (
    "fmt"
    "strconv"
)

var damm = [10][10] int {
    {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
    {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
    {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
    {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
    {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
    {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
    {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
    {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
    {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
    {2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
}

func is_valid(num int) bool {
    var n_str = strconv.Itoa(num)
    var temp = 0
    for _, ch := range n_str {
        temp = damm[temp][ch-'0']
    }
    return temp == 0
}

func main() {
    fmt.Println("Valid numbers between 5700 and 5800 are:")
    for i := 5700; i <= 5800; i++ {
        if is_valid(i) {
            fmt.Printf("%d ", i)
        }
    }
    fmt.Println("")
}

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Java

public class DammCheckDigit {
    private static final int[][] damm = 
        { {0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
          {7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
          {4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
          {1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
          {6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
          {3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
          {5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
          {8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
          {9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
          {2, 5, 8, 1, 4, 3, 6, 7, 9, 0} };

    private static boolean is_valid(Integer num) {
        char[] n = num.toString().toCharArray();
        int temp = 0;
        for (char ch : n) {
            temp = damm[temp][ch - '0'];
        }
        return temp == 0;
    }

    public static void main(String[] args) {
        System.out.printf("%s", "Valid numbers between 5700 and 5800 are:");
        for(int i = 5700; i <= 5800; i++) {
            if (is_valid(i))  System.out.printf("%d ", i);
        }
        System.out.printf("%s", "\n");
    }
}

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in JavaScript

damm = [ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
         [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
         [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
         [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
         [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
         [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
         [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
         [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
         [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
         [2, 5, 8, 1, 4, 3, 6, 7, 9, 0] ];

function is_valid (n) {
    let digits = n.toString().split("")
    var temp = 0
    for (var i = 0; i < digits.length; i++) {
        temp = damm[temp][digits[i]]
    }
    return temp == 0
}

console.log("Valid numbers between 5700 and 5800 are:")
for (var i = 5700; i <= 5800; i++) {
    if (is_valid(i)) {
        process.stdout.write(i + " ")
    }
}
console.log("")

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Julia

Julia array indices start at 1, not 0, so the crucial code line (temp = damm[temp + 1][d - '0' + 1]) needs to add 1 to the array subscripts when retrieving values from the damm matrix.

function is_valid(num)
    damm = (
        (0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
        (7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
        (4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
        (1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
        (6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
        (3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
        (5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
        (8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
        (9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
        (2, 5, 8, 1, 4, 3, 6, 7, 9, 0))
    temp = 0
    str = string(num)
    for d in str
        temp = damm[temp + 1][d - '0' + 1]
    end
    return temp == 0
end

println("Valid numbers between 5700 and 5800 are: ")
for i in 5700:5800
    if is_valid(i)
        print("$i ")
    end
end
println("")

Output:

$ julia ./damm-algo.jl
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Kotlin

Declaring and initializing a matrix in Kotlin is somewhat painful, but the code is otherwise fairly straight forward.

val damm = arrayOf(
    intArrayOf(0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
    intArrayOf(7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
    intArrayOf(4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
    intArrayOf(1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
    intArrayOf(6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
    intArrayOf(3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
    intArrayOf(5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
    intArrayOf(8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
    intArrayOf(9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
    intArrayOf(2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
)

fun is_valid(num: Int): Boolean {
    val n_str = num.toString()
    var temp = 0
    for (d in n_str) {
        temp = damm[temp][d - '0']
    }
    return temp == 0
}

fun main() {
    println("Valid numbers between 5700 and 5800 are: ")
    for (i in 5700..5800) {
        if (is_valid(i)) print("$i ")
    }
    println("")
}

Output:

Valid numbers between 5700 and 5800 are: 
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Lua

Like in Julia, Lua array indices start at 1, not 0, so the crucial code line (temp = damm[temp + 1][ch + 1]) needs to add 1 to the array subscripts when retrieving values from the damm matrix.

local damm = {
    {0,3,1,7,5,9,8,6,4,2},
    {7,0,9,2,1,5,4,8,6,3},
    {4,2,0,6,8,7,1,3,5,9},
    {1,7,5,0,9,8,3,4,2,6},
    {6,1,2,3,0,4,5,9,7,8},
    {3,6,7,4,2,0,9,5,8,1},
    {5,8,6,9,7,2,0,1,3,4},
    {8,9,4,5,3,6,2,0,1,7},
    {9,4,3,8,6,1,7,2,0,5},
    {2,5,8,1,4,3,6,7,9,0}
}
function is_valid(num)
    local n_str = tostring(num)
    local temp = 0
    for ch in n_str:gmatch"." do
        temp = damm[temp + 1][ch + 1]
    end
    return temp == 0
end

print("Valid numbers between 5700 and 5800 are: ")
for i = 5700, 5800 do
    if is_valid(i) then
        io.write(i, " ")
    end
end
print("")

Output:

Valid numbers between 5700 and 5800 are: 
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Nim

Remember that Nim control flow is indentation-based, like Python.

import strutils

let damm = [ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
             [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
             [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
             [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
             [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
             [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
             [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
             [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
             [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
             [2, 5, 8, 1, 4, 3, 6, 7, 9, 0] ]

proc is_valid(num: int): bool =
  let n_str = intToStr(num)
  var temp = 0
  for i in 0..len(n_str) - 1:
    temp = damm[temp][int(n_str[i]) - 48]
  return temp == 0

echo "Valid numbers between 5700 and 5800 are:"
for i in 5700..5800:
  if is_valid(i):
    stdout.write i, " "
echo ""

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Pascal

I’m not particularly fond of Pascal, which I found too verbose (at least, by today’s criteria), and I’ve never used it for real-life projects (well, except some quite small Delphi projects a number of decades ago). But, having said that, I must add that Pascal is nonetheless a soft point for me, as it is the first language that I learned in my IS studies (although I had programmed as an autodidact before starting my studies, in Basic, in C, and in the pseudo-assembler of programmable pocket calculators). Pascal is quite clean (perhaps too clean) and it is with Pascal that I first learned the tenets of structured programming. Other languages that I used at the time and found interesting were Fortran, Ada, Prolog, Caml, and especially Modula-2 (or, was it Modula-3? Quite possibly both, one after the other. I’m not quite sure). I might try implementations in some of these languages some day, although I have forgotten most about them. Another language that I also (vaguely) learned at the time of my early studies is Cobol, but I disliked it so much that it is very unlikely that I will ever try to code something in it in the future.

program DammCheckDigit;
uses
  sysutils;

const damm : array[0..9,0..9] of integer =
    ( (0,3,1,7,5,9,8,6,4,2),
      (7,0,9,2,1,5,4,8,6,3),
      (4,2,0,6,8,7,1,3,5,9),
      (1,7,5,0,9,8,3,4,2,6),
      (6,1,2,3,0,4,5,9,7,8),
      (3,6,7,4,2,0,9,5,8,1),
      (5,8,6,9,7,2,0,1,3,4),
      (8,9,4,5,3,6,2,0,1,7),
      (9,4,3,8,6,1,7,2,0,5),
      (2,5,8,1,4,3,6,7,9,0) );

function is_valid(num : integer) : boolean;
var
    temp, i : integer;
    n_str : string;
begin
    n_str := inttostr(num);
    temp := 0;
    for i := 0 to length(n_str) do
    begin
        temp := damm[temp, ord(n_str[i]) - ord ('0')];
    end;
    is_valid := temp=0;
end;

var
    i : integer;
begin
    writeln('Valid numbers between 5700 and 5800 are:');
    for i := 5700 to 5800 do
    begin
        if is_valid(i) then
             write(i, ' ');
    end;
    writeln
end.

{
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797 
}

Damm Algorithm in Python

damm = (
    (0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
    (7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
    (4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
    (1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
    (6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
    (3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
    (5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
    (8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
    (9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
    (2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
)

def is_valid(num: int) -> bool:
  temp = 0
  for d in str(num):
    temp = damm[temp][int(d)] 
  return temp == 0

print("Valid numbers between 5700 and 5800 are:")
for i in range(5700, 5801):
  if is_valid(i):
    print(i, end=' ')
print("")

Output:

$ python3 ./damm-algo.py
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Ring

Like in Julia and Lua, array indices start at 1, not 0, so the crucial code line (temp = damm[temp + 1][ch - '0' + 1]) needs to add 1 to the array subscripts when retrieving values from the damm matrix.

damm = [ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
         [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
         [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
         [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
         [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
         [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
         [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
         [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
         [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
         [2, 5, 8, 1, 4, 3, 6, 7, 9, 0] ]

see "Valid numbers between 5700 and 5800 are:" + nl
for i = 5700 to 5800
    if is_valid(i)
        see "" + i + " "
    ok
next
see " " + nl

func is_valid(num)
    temp = 0
    n = string(num)
    for ch in n
        temp = damm[temp + 1][ch - '0' + 1]
    next
    return temp = 0

Output:

$ ring ./damm-algo.ring
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Ruby

The Ruby implementation is very simple and very concise, thanks to the built-in digits function. Note, however, that this function returns the digits in an inverse order, so we need to reverse it.

def is_valid (n)
    damm = [ [0,3,1,7,5,9,8,6,4,2],
             [7,0,9,2,1,5,4,8,6,3],
             [4,2,0,6,8,7,1,3,5,9],
             [1,7,5,0,9,8,3,4,2,6],
             [6,1,2,3,0,4,5,9,7,8],
             [3,6,7,4,2,0,9,5,8,1],
             [5,8,6,9,7,2,0,1,3,4],
             [8,9,4,5,3,6,2,0,1,7],
             [9,4,3,8,6,1,7,2,0,5],
             [2,5,8,1,4,3,6,7,9,0] ]
    temp = 0
    for ch in n.digits.reverse
        temp = damm[temp][ch]
    end
    return temp == 0
end

puts("Valid numbers between 5700 and 5800 are:")
for i in 5700..5800
    if is_valid(i)
        printf("%d ", i)
    end
end
puts("")

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Rust

fn is_valid(num: u32) -> bool {
    static DAMM: [[u8; 10]; 10] = [
        [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
        [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
        [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
        [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
        [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
        [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
        [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
        [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
        [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
        [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
    ];

    let mut temp = 0;
    let n_str = num.to_string();
    let digits = n_str.bytes();
    for i in digits {
        temp = DAMM[temp as usize][i as usize - 48];
    };
    return temp == 0
}

fn main() {
    println!("{}", "Valid numbers between 5700 and 5800 are:");
    for i in 5700..5800 {
        if is_valid(i) {
            print!("{} ", i);
        }
    }
    println!("{}", " ");
}

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Scala

object DammCheckDigit extends App {
  var damm =
    Vector(
      Vector(0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
      Vector(7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
      Vector(4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
      Vector(1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
      Vector(6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
      Vector(3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
      Vector(5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
      Vector(8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
      Vector(9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
      Vector(2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
    )

  def is_valid(num: Int): Boolean = {
    val num_str = num.toString.getBytes
    var temp = 0
    for (ch <- num_str) {
      temp = damm(temp)(ch - '0')
    }
    return temp == 0
  }

  println("Valid numbers between 5700 and 5800 are:")
  for (i <- 5700 to 5800) {
    if (is_valid(i)) {
      printf("%d ", i)
    }
  }
  println("")
}

Output:

Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Damm Algorithm in Tcl

As in awk and Dart, I haven’t found a good way to declare and initialize two-dimensional arrays in Tcl, and the documentation is quite sparse. So I used the same solution as in awk and Dart for the conversion matrix: an array of strings. My knowledge of Tcl dates from the 1990s and is very rusty, so I initially had an interpreter error on almost every code line. So, be aware that my implementation certainly doesn’t satisfy the best practices of this language.

proc is_valid {n} {
    set damm(0) "0317598642"
    set damm(1) "7092154863"
    set damm(2) "4206871359"
    set damm(3) "1750983426"
    set damm(4) "6123045978"
    set damm(5) "3674209581"
    set damm(6) "5869720134"
    set damm(7) "8945362017"
    set damm(8) "9438617205"
    set damm(9) "2581436790"

    set temp 0
    foreach ch [split $n {}] {
        set row $damm($temp)
        set temp [ string index $row $ch ]
    }
    return [ expr $temp == 0 ? 1 : 0]
}

puts "Valid numbers between 5700 and 5800 are: "
for {set i 5700} {$i <= 5800} {incr i} {
    if [ is_valid $i ] {
        puts -nonewline  "${i} "
    }
}
puts ""

Output:

$ tclsh ./damm-algo.tcl
Valid numbers between 5700 and 5800 are:
5708 5719 5724 5735 5743 5756 5762 5770 5781 5797

Task 2: Palindromic Prime Cyclops

Write a script to generate first 20 Palindromic Prime Cyclops Numbers.

A cyclops number is a number with an odd number of digits that has a zero in the center only.

Output

101, 16061, 31013, 35053, 38083, 73037, 74047, 91019, 94049,
1120211, 1150511, 1160611, 1180811, 1190911, 1250521, 1280821,
1360631, 1390931, 1490941, 1520251

Palindromic Prime Cyclops in Raku

In order to reduce the pointless computations, we’ll only test number ranges with an odd number of digits (100..999, 10000..99999, 1000000..9999999). As it turns out, the process is quite fast (about 2.6 seconds), so that performance enhancement wasn’t really required. I find it nonetheless better to avoid useless computations.

sub is-cyclops ($n) {
    my $length = $n.chars;
    return False if $length %% 2;
    my $mid = ($length - 1) /2;
    return False if substr($n, $mid, 1) != 0;
    return False if $n.comb[0..$mid-1] ~~ /0/;
    return False if $n.comb[$mid+1..$length-1] ~~ /0/;
    return True;
}

my $count = 0;
for |(100..999), |(10000..99999), |(1000000..9999999) -> $i {
    next unless $i eq $i.flip;
    next unless $i.is-prime;
    if is-cyclops $i {
        print "$i ";
        $count++;
        last if $count == 20;
    }
}
say "";

This program displays the following output:

$ time raku ./cyclops.raku
101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

real    0m2,573s
user    0m0,015s
sys     0m0,015s

Palindromic Prime Cyclops in Perl

This is a port to Perl of the Raku program above. Since Perl doesn’t have a built-in is_prime subroutine, we roll out our own.

use strict;
use warnings;
use feature qw/say/;

sub is_cyclops {
    my $n = shift;
    my $len = length $n;
    return 0 if $len % 2 == 0;
    my $mid = ($len - 1) /2;
    return 0 if substr($n, $mid, 1) != 0;
    return 0 if (split //, $n)[0..$mid-1] =~ /0/;
    return 0 if (split //, $n)[$mid+1..$len-1] =~ /0/;
    return 1;
}

sub is_prime {
   my $n = shift;
   return 1 if $n == 2;
   return 0 if $n % 2 == 0;
   return 0 if $n == 1;
   my $p = 3;
   my $sqrt = sqrt $n;
   while ($p <= $sqrt) {
       return 0 if $n % $p == 0;
       $p += 2;
   }
   return 1;
}

my $count = 0;
for my $i (100..999, 10000..99999, 1000000..9999999) {
    next unless $i eq reverse $i;
    next unless is_cyclops $i;
    if (is_prime $i) {
        print "$i ";
        $count++;
        last if $count == 20;
    }
}

This program displays the following output:

$ perl ./cyclops.pl
101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Other Languages

We now present the same palindromic prime cyclop implementations in the following 8 guest languages:

  • Julia
  • JavaScript
  • Kotlin
  • Lua
  • Python
  • Ring
  • Ruby
  • Coconut

Palindromic Prime Cyclops in Julia

I like the concision of Perl and Raku postfix conditionals such as:

return False if substr($n, $mid, 1) != 0;
return False if $n.comb[0..$mid-1] ~~ /0/;
return False if $n.comb[$mid+1..$length-1] ~~ /0/;
return True;

In most other languages, you would need three code lines for each case, for example in JavaScript:

if (s[mid] != '0') {
    return false
}
if (s.slice(0, mid-1).search('0') >= 0) {
    return false
}
if (s.slice(mid+1).search('0') >= 0) {
    return false
}
return true

Julia doesn’t have postfix conditionals, but you can use short-circuit evaluation of the && and || operators as an alternative to short if statements to reach the same concision.

The short-circuit evaluation, which is common to most imperative programming languages, means that:

  • In the expression a && b, the subexpression b is only evaluated if a evaluates to true.
  • In the expression a || b, the subexpression b is only evaluated if a evaluates to false.

Instead of if <cond> <statement> end, one can write <cond> && <statement> (which could be read as: <cond> and then <statement>). Similarly, instead of if ! <cond> <statement> end, one can write || (which could be read as: <cond> or else <statement>). This idiomatic alternative to short if statement is frequently used in Julia. Although most languages have the short-circuit behavior of logical operators, not many of them support this construct with an ending statement. Raku and Perl do, but this is not commonly used because the return false if ... is admittedly clearer. In the seven guest languages used here, only Kotlin also supports this construct.

So, in Julia, we will have, for example:

len % 2 == 0 && return false
...
s[mid] == '0' || return false

This is our Julia implementation using this concise construct:

using Primes

function is_cyclops(n)
    s = string(n)
    len = length(s)
    len % 2 == 0 && return false
    mid = Int((len + 1) /2)
    s[mid] == '0' || return false
    if occursin('0', s[1:mid-1]) || occursin('0', s[mid+1:len])
        return false
    end
    return true;
end

count = 0
for i = [101:999; 10000:99999; 1000000:9999999]
    string(i) != reverse(string(i)) && continue
    is_cyclops(i) || continue
    if isprime(i)
        print("$i ")
        global count += 1
        count >= 20 && break
    end
end
println("")

Output:

$ julia ./cyclop.jl
101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in JavaScript

JavaScript doesn’t have a built-in function for prime numbers (just as almost all other guest languages to follow). So we roll out our own is_prime function (ported from the Perl implementation above).

It also doesn’t seem possible to combine ranges as we’ve done previously in other languages, so we use a if ... else if ... else if ... construct to simulate range concatenation.

function is_cyclops (n) {
    let s = n.toString()
    let len = s.length
    if (len % 2 == 0) {
        return false
    }

    let mid = (len - 1) / 2
    if (s[mid] != '0') {
        return false
    }

    if (s.slice(0, mid-1).search('0') >= 0) {
        return false
    }
    if (s.slice(mid+1).search('0') >= 0) {
        return false
    }
    return true
}

function is_prime(n) {
    if (n == 2) {
        return true
    }
    if (n < 2 || n % 2 == 0) {
        return false
    }
    var p = 3
    let sqrt_n = Math.sqrt(n)
    while (p <= sqrt_n) {
        if (n % p == 0) {
            return false
        }
        p += 2
    }
    return true
}

var count = 0
var i = 100
while (count < 20) {
    i++
    if (i == 999) {
        i = 10000
    } else if (i == 99999) {
        i = 1000000
    } else if (i >= 9999999) {
        break
    }
    if (i.toString() != i.toString().split("").reverse().join("")) {
        continue;
    }
    if (! is_cyclops(i)) {
        continue;
    }
    if (is_prime(i)) {
        process.stdout.write(i + " ")
        count++
    }
}
console.log("")

Output:

101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Kotlin

I do not know whether the short-circuit evaluation alternative to short if statement described above in the context of the Julia language is as commonly used in Kotlin as it is in Julia, but, since it works in Kotlin, I’ll use it here. Also note that we need to implement our own is_prime function in Kotlin.

fun is_prime(n: Int): Boolean {
    n == 2 && return true
    if (n < 2 || n % 2 == 0) {
        return false
    }
    var p = 3
    val sqrt_n : Int = Math.sqrt(n.toDouble()).toInt()
    while (p <= sqrt_n) {
        n % p == 0 && return false
        p += 2
    }
    return true
}

fun is_cyclops(num: Int): Boolean {
    val s = num.toString()
    val len = s.length
    len % 2 == 0 && return false
    val mid = ((len - 1) /2).toInt()
    s[mid] == '0' || return false
    if ('0' in s.slice(0 until mid) or '0' in s.slice(mid+1 until len) {
        return false
    }
    return true
}

fun main() {
    var count = 0
    var i = 100
    while (count < 20) {
        i++
        if (i == 999) {
             i = 10000
        } else if (i == 99999) {
            i = 1000000
        } else if (i >= 9999999) {
            break
        }
        if (i.toString() != i.toString().reversed()) {
            continue;
        }
        if (! is_cyclops(i)) {
            continue;
        }
        if (is_prime(i)) {
            print("$i ")
            count++
        }
    }
    println(" ")
}

Output:

    101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Lua

Lua doesn’t have a next or continue statement to go directly to the next iteration of a loop, because “the language is designed to be small.” I’m not sure it is a very good reason, as, in my humble opinion, this kind of statement is very useful. This is the reason for which we have two goto skip statements in the main part of the program. I know very well what Edsger Dijkstra said in his famous letter to ACM “Go To Statement Considered Harmful,” but Donald Knuth commented that a “goto forward” within the same routine wasn’t that bad. This is the case here. Having said that, I would definitely prefer if Lua had a continue or next statement rather than a goto statement.

We also have to implement a is_prime function here.

local function is_cyclops(num)
    local n_str = tostring(num)
    size = string.len(n_str)
    if size % 2 == 0 then
        return false
    end
    mid = (size + 1) / 2
    if string.sub(n_str, mid, mid ) ~= '0' then
        return false
    end
    if string.sub(n_str, 1, mid-1):find "0" ~= nil then
        return false
    end
    if string.sub(n_str, mid+1, len):find "0" ~= nil then
        return false
    end
    return true
end

local function is_prime(n)
    if n == 2 then
        return true
    end
    if n < 2 or n % 2 == 0 then
        return false
    end
    local p = 3
    sqrt_n = math.sqrt(n)
    while p <= sqrt_n do
        if n % p == 0 then
            return false
        end
        p = p + 2
    end
    return true
end

count = 0
i = 100
while count < 20 do
    i = i + 1
    if i == 999 then
        i = 10000
    elseif i == 99999 then
        i = 1000000
    elseif i >= 9999999 then
        break
    end

    if i ~= tonumber(string.reverse(tostring(i))) then
        goto skip
    end
    if not is_cyclops(i) then
        goto skip
    end
    if is_prime(i) then
        io.write(i, " ")
        count = count + 1
    end
    ::skip::
end
print("")

Output:

101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Python

import math
from re import search
from itertools import chain

def is_prime(n):
  if n == 2:
    return True
  if n == 0 or n == 1 or n % 2 == 0:
    return False
  p = 3
  sqrt_n = math.sqrt(n)
  while (p <= sqrt_n):
    if ((n % p) == 0):
      return False
    p += 2
  return True

def is_cyclops (num):
  s = str(num)
  size = len(s)
  if size % 2 == 0:
    return False
  mid = int((size - 1) / 2)
  if s[mid] != '0':
    return False
  if search(r"0", s[0:mid-1]) or search(r"0", s[mid+1:size-1]):
    return False
  return True

count = 0
myrange = chain(range(100, 999), range(10000, 99999), range(1000000, 9999999))
for i in myrange:
  if str(i) != str(i)[::-1]:
    continue
  if not is_cyclops(i):
    continue
  if is_prime(i):
    print(i, end=' ')
    count += 1
    if count >= 20: 
      break

print("")

Output:

$ python3 ./cyclop.py
101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Ring

As far as I can tell, Ring also doesn’t have continue or next statements (and also no last and no break). Or, at least, I couldn’t find them (or an equivalent) in the documentation. So I had to use nested if statements, something that I don’t like too much. It also appears that there is no built-in function for reversing a string, so I wrote a is_palindrome function. And also a is_prime function. Also note that the equality operator (== in many languages) is spelled with a single equal sign in Ring, so we have for example if n % p = 0. I wonder how the compiler can distinguish it from the assignment operator, there must be some cases that are ambiguous.

i = 100
count = 0
while count < 20
    i++
    if i = 999
        i = 10000
    ok
    if i = 99999
        i = 1000000
    ok
    if is_palindrome(i)
        if is_cyclops(i)
            if is_prime(i)
                count++
                see "" + i + " "
            ok
       ok
   ok
end
see "" + nl

func is_prime (n)
    if n = 2 
        return true
    ok
    if n < 2 or n % 2 = 0
        return false
    ok
    p = 3
    sqrt_n = sqrt(n)
    while p < sqrt_n
        if n % p = 0
            return false
        ok
        p++
    end
    return true

func is_cyclops(n)
    s = "" + n
    size = len(s)
    if size % 2 = 0
        return false
    ok
    mid = ( size + 1) / 2
    if s[mid] != 0
        return false
    ok

    if substr(left(s, mid-1), "0") > 0
        return false
    ok
    if substr(right(s, mid-1), "0") > 0
        return false
    ok
    return true

func is_palindrome(n)
    s = "" + n
    size = len(s)
    for i = 1 to size/2
        if s[i] != s[size - i + 1]
            return false
        ok
    next
    return true

Output:

$ ring  ./cyclop.ring
101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Ruby

Ruby has a built-in prime function, so we don’t need to implement it. I found a way to combine ranges, but I must admit that this is copied from a post on Stack Overflow, I would not have found it by myself.

require 'prime'

def is_cyclops (num) 
    s = num.to_s
    len = s.length;
    if len % 2 == 0 then
        return false
    end
    mid = (len - 1) / 2
    if s[mid] != '0' then
        return false
    end
    if s[0..mid-1][/0/] || s[mid+1..len-1][/0/]
        return false
    end 
    return true
end

count = 0;
range = [ 100..999, 10000..99999, 1000000..9999999 ].map { |r| Array(r) }.inject( :+ )
for i in range
    if i.to_s != i.to_s.reverse || ! is_cyclops(i)
        next
    end
    if i.prime?
        printf("%d ", i)
        count += 1;
        if count == 20
            break
        end
    end
end
puts ""

Output:

101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

Palindromic Prime Cyclops in Coconut (a Functional Extension of Python)

This section on Coconut was added on August 18, 2022.

Coconut is a variant of Python built for functional programming. It is actually a kind of extension of Python, and Coconut code is in fact compiled to Python code. The documentation is still somewhat limited, but there is a good Coconut Tutorial and a reference Coconut Documentation.

I was interested in trying to use Coconut for this task essentially because of its support to pipeline style programming. Since we’re looking for the first twenty integers having a certain set of properties (prime, palindromic, with an odd number of digits, with a 0 in the middle and no other 0, etc.), it is appealing to use a pipeline of filters, one for each of these properties, as done in the last (main) section of the code below.

import math
from re import search

def is_prime(n):
    case n:
        match 0:
            return False
        match 1:
            return False
        match 2:
            return True
        match _ is int if n > 2:
            if n % 2 == 0:
                return False
            p = 3
            sqrt_n = math.sqrt(n)
            while (p <= sqrt_n):
                if (n % p) == 0:
                    return False
                p += 2
            return True

def is_cyclops (num):
  s = str(num)
  size = len(s)
  mid = int((size - 1) / 2)
  if s[mid] != '0':
    return False
  if search(r"0", s[0:mid-1]) or search(r"0", s[mid+1:size-1]):
    return False
  return True

range(100, 999) :: range(10000, 99999) :: range(1000000, 9000000) \
|> filter$( -> str(_) == str(_)[::-1]) \    # palindrome
|> filter$( -> len(str(_)) %2 != 0) \       # odd number of digits
|> filter$(is_cyclops) |> filter$(is_prime) \
|>  list |> .$[:20] |> print

Output:

101 16061 31013 35053 38083 73037 74047 91019 94049 1120211 1150511 1160611 1180811 1190911 1250521 1280821 1360631 1390931 1490941 1520251

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 August 21, 2022. And, please, also spread the word about the Perl Weekly Challenge if you can.

# Perl Weekly Challenge 176: Permuted Multiples and Reversible Numbers

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

Spoiler Alert: This weekly challenge deadline is due in a few of days from now (on Aug. 7, 2022 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: Permuted Multiples

Write a script to find the smallest positive integer x such that x, 2x, 3x, 4x, 5x and 6x are permuted multiples of each other.

For example, the integers 125874 and 251748 are permuted multiples of each other as

251784 = 2 x 125874

and also both have the same digits but in different order.

Output

142857

In Raku, Perl, and some other programming languages, conversions between numbers and strings are simple or even implicit and automatic. This task will be very easy for them. In some other languages, the strong typing system might make it more difficult. In such an event, we may also use a purely arithmetic method to retrieve the individual digits (see for example the C and bc implementations). This may have an impact on my choice of guest languages: I will not try guest languages that are crippled by a type system straitjacket.

Permuted Multiples in Raku

We’re essentially trying to find if the first six integer multiples of an integer are anagrams of each other. One way to go might be to store the individual digits in a hash and check whether we have the same digits. But it’s not so easy when the input number has twice or several times the same digit. It is usually easier (and probably faster) to reduce the input number to a normalized form (for example with the digits rearranged in ascending order) and to compare the normalized form of the input number with the normalized forms of the multiples. In the program below, the ordered variable is a string in which the digits of the input integer have been rearranged in ascending order. At the end, we only need a string comparison to find out whether the various integers have the same digits.

sub check_multiples ($j) {
    my $ordered = join '', $j.comb.sort;
    for 2..6 -> $k {
        return False if ($k * $j).comb.sort.join ne $ordered;
    }
    return True;
}

.say and last if check_multiples $_ for 1..Inf;

This program displays the following output:

$ time raku ./permuted-multiples.raku
142857

real    0m3,370s
user    0m0,015s
sys     0m0,088s

We can significantly improve performance by adding one code line at the beginning of the check_multiples subroutine:

sub check_multiples ($j) {
    return False if $j.chars != (6 * $j).chars; 
    my $ordered = join '', $j.comb.sort;
    for 2..6 -> $k {
        return False if ($k * $j).comb.sort.join ne $ordered;
    }
    return True;
}

By returning early from the subroutine when the length of 6 * $j is more than the length of $j we save quite a bit of useless computations. The execution time goes down to 1.390 sec. Another possibility would be to reverse the tests in the for loop, i.e. to go down from 6 to 2.

Permuted Multiples in Perl

This is a port to Perl of the Raku program above. Please refer to the description in the Raku section above in you need explanations.

use strict;
use warnings;
use feature qw/say/;

sub check_multiples {
    my $j = shift;
    my $ordered = join '', sort split //, $j;
    for my $k (2..6) {
        return 0 if $ordered ne join '', sort {$a cmp $b}  split //, ($k * $j);
    }
    return 1;
}

my $i = 1;
while (1) {
    if (check_multiples $i) {
        say $i;
        last;
    }
    $i++;
}

This program displays the following output:

$ time perl  permuted-multiples.pl
142857

real    0m0,604s
user    0m0,546s
sys     0m0,046s

The Perl code is a bit longer than the Raku code, but the Perl program runs 5,6 times faster.

Permuted Multiples in Julia

In Julia, the built-in digits function returns the digits of a number. No need for conversions between integer and string and the other way around, and this leads to a quite concise program.

function check_multiples(n)
    ordered = sort(digits(n))
    for j in 2:6
        if sort(digits(n * j)) != ordered
            return false
        end
    end
    return true
end

i = 1
while true
    if check_multiples(i)
        println(i)
        break
    end
    global i += 1
end

Output:

$ julia .\permuted-multiples.jl
142857

Permuted Multiples in Python

def check_multiples(n):
  input = [int(c) for c in str(n)]
  input.sort()
  for i in range(2, 7):
    test = [int(c) for c in str(n * i)]
    test.sort()
    if input != test:
      return False
  return True


i = 2
while True:
  if check_multiples(i):
    print(i)
    break
  i += 1

Output:

$ time python3 ./permuted-multiples.py
142857

real  0m0,745s
user  0m0,640s
sys   0m0,077s

Permuted Multiples in awk

The awk language is relatively slow, so I added a test:

        if (length(test) != len) {
           return 0
        }

before the inner for loop to immediately go out of the loop and avoid the digit-by-digit comparison if the length of tested number is not the same as the length of the input number.

function check_multiples(n) {
    split(n, ordered, "")
    asort(ordered)
    len = length(ordered)
    for (j = 2; j <= 6; j++) {
        split(n * j, test, "")
        asort(test)
        if (length(test) != len) {
           return 0
        }
        for (k = 1; k <= len; k++) {
            if (ordered[k] != test[k]) {
                return 0
            }
        }
    }
    return 1
} 

BEGIN  {
    i = 1
    while (1) {
        if (check_multiples(i)) {
            print i
            break
        }
    i++
    }
}

With the performance improvement described above, the runtime is quite good:

$ time awk -f permuted-multiples.awk
142857

real    0m1,498s
user    0m1,343s
sys     0m0,015s

However, we can improve it by making the test earlier in the check_multiples function:

function check_multiples(n) {
    if (length(n) != length(6 * n)) {
        return 0
    }
    split(n, ordered, "")
    asort(ordered)
    len = length(ordered)
    for (j = 2; j <= 6; j++) {
        split(n * j, test, "")
        asort(test)
        for (k = 1; k <= len; k++) {
            if (ordered[k] != test[k]) {
                return 0
            }
        }
    }
    return 1
}

With this change, the output is now this:

$ time awk -f permuted-multiples.awk
142857

real    0m0,653s
user    0m0,624s
sys     0m0,031s

That’s 2.3 times faster. Not bad.

Permuted Multiples in C

The C implementation is quite verbose (and sort of a pain in the neck to get it right) compared to other languages, but I decided not to criticize this aspect any further when I saw the performance (barely more than 1/10 sec. runtime):

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int comp (const void * elem1, const void * elem2) {
    int f = *((int*)elem1);
    int s = *((int*)elem2);
    if (f > s) return  1;
    if (f < s) return -1;
    return 0;
}

int normalize (int num) {
    int n = num;
    int len = n <= 9 ? 1 : floor(log10(n)) + 1;
    int d[len];  // array of digits of input number
    char st[len];
    int i = 0;
    while (n > 0) {
        d[i] = n % 10;
        n /= 10;
        i++;
    }
    qsort (d, sizeof(d)/sizeof(*d), sizeof(*d), comp);
    int norm = 0;
    int j = 1;
    for (int i = len - 1; i >= 0; i--) {
        norm += d[i] * j;
        j *= 10;
    }
    return norm;
}

int permuted_multiples (int n) {
    int norm_in = normalize(n);
    for (int i = 6; i > 2; i--) 
        if (normalize(n * i) != norm_in) return 0;
    return 1;
}

int main () {
    int i = 1;
    while (1) {
        if (permuted_multiples(i)) {
            printf("%d\n", i);
            break;
        }
        i++;
    }
}

Output:

$ time ./a.out
142857

real    0m0,112s
user    0m0,078s
sys     0m0,000s

Permuted Multiples in D

D is similar to C, but with less pointer hassle and more built-in functions, making the syntax simpler:

import std.stdio;
import std.conv, std.array;
import std.algorithm;

int normalize(int num) {
    string n = to!string(num, 10);
    ulong len = n.length;
    string[] d = n.split("");
    d.sort();
    return to!int(d.joiner);
}

bool permuted_multiples (int n) {
    int norm_in = normalize(n);
    for (int i = 6; i > 2; i--) 
        if (normalize(n * i) != norm_in) return false;
    return true;
}

void main() {
    int i = 1;
    while (true) {
        if (permuted_multiples(i)) {
            printf("%d\n", i);
            break;
        }
        i++;
    }
    writeln(" ");
}

This program also displays 142857 and runs in .44 second (don’t compare with C, though, the timings are not equivalent for various reasons).

Task 2: Reversible Numbers

Write a script to find out all Reversible Numbers below 100.

A number is said to be a reversible if sum of the number and its reverse had only odd digits.

For example,

36 is reversible number as 36 + 63 = 99 i.e. all digits are odd.
17 is not reversible as 17 + 71 = 88, none of the digits are odd.

Output:

10, 12, 14, 16, 18, 21, 23, 25, 27,
30, 32, 34, 36, 41, 43, 45, 50, 52,
54, 61, 63, 70, 72, 81, 90

Reversible Numbers in Raku

I first thought about using junctions to check whether all of the digits of the resulting number are odd (or, alternatively, whether any of the digits is even), but it rapidly occurred to me that a regex character class with all even digits is sort of equivalent to a junction with even digits, and that a regex solution would be much simpler (and, by the way, that the same solution could also be used in Perl (and possibly some other languages).

This leads to the following very simple code:

print "$_ " unless $_ + .flip ~~ /<[02468]>/ for 1..100;

Used as a Raku one-liner, we obtain the following output:

$ raku -e 'print "$_ " unless $_ + .flip ~~ /<[02468]>/ for 1..100;'
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Perl

The Perl solution also uses a regex and an even-digit character class to do the job:

for (1..100) {print "$_ " unless ($_ + reverse $_) =~ /[02468]/}

Used as a Perl one-liner, we obtain the following output:

$ perl -e 'for (1..100) {print "$_ " unless ($_ + reverse $_) =~ /[02468]/}'
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Julia

Julia uses the Perl Compatible Regular Expressions (PCRE) library to handle regexes. The occursin function returns a Boolean value telling us whether the regex pattern was found. This is almost as easy as in Raku and Perl

for i in 1:100
    sum = i + parse(Int32, reverse(string(i)))
    if ! occursin(r"[02468]", string(sum))
        print("$i ")
    end
end
println(" ")

Output:

$ julia .\reversible.jl
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in C

The C language doesn’t have a standard string reverse function (although some implementations have it). So, we have to write one. Otherwise, we convert the integer sum to a string (using the sprintf function) and loop through the digits to check whether any of them is even, and return a false value (0) if such is the case.

int reverse(int n) {
    char st[10];
    char r[10];
    int len = sprintf(st, "%d", n);   // convert input int to string
    for (int i = 0; i < len; i++) {
        r[len - i - 1] = st[i];
    }
    r[len] = '\0';
    return atoi(r);
}

int is_reversible(int n) {
    char sum[10];
    int length =  sprintf(sum, "%d", n + reverse(n));
    for (int k = 0; k < length; k++) {
        if (sum[k] % 2 == 0) {
            return 0;
        }
    }
    return 1;
}

int main () {
    for (int i = 1; i < 100; i++) {
        if (is_reversible(i)) {
            printf("%d ", i);
        }
    }
    printf("%s\n", "");
}

Output:

$ ./a.out
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

C compared to Perl or Raku

If you compare this 35-line C solution with the Raku or Perl one-liners shown above, you’ll probably understand why Raku and Perl are my favorite programming languages. Having said that, I should add that C, which was created in the early 1970s and is still very much in use half a century later, is sort of the mother of all languages (even the Perl interpreter is written mostly in C). And, as seen above in the context of the first task of this challenge, C is very fast.

For those of you old enough to remember the Usenet newsgroups, let me share this pearl of wisdom dating from the late 1990s.

A Tribute to the Beatles “Let It Be” (and to Dennis M. Ritchie).

To the tune of “Let It Be”.

To listen to it, go there.

When I find my code in tons of trouble, Friends and colleagues come to me, Speaking words of wisdom: Write in C.

As the deadline fast approaches, And bugs are all that I can see, Somewhere, someone whispers: Write in C.

Write in C, write in C, Write in C, oh, write in C. LOGO’s dead and buried, Write in C.

Reversible Numbers in D

The D programming language boasts to combine the performance and safety of compiled languages (such as C or C++) with the expressive power of modern dynamic and functional programming languages. The syntax is relatively close to C, but the program is notably shorter than its C counterpart. Here, we have methods to reverse a string (retro) and to easily convert integers to strings or strings to integers. As with our C implementation, we loop through the digits to check whether any of them is even, and return false if such is the case.

import std.stdio;
import std.conv, std.range;

bool is_reversible(int n) {
    string s = to!string(n, 10);
    string rev = s.retro.text;
    string sum = to!string(n + to!int(rev), 10);
    for (int k = 0; k < sum.length; k++) {
        if (sum[k] % 2 == 0) {
            return false;
        }
    }
    return true;
}

void main() {
    for (int i = 1; i < 100; i++) {
        if (is_reversible(i)) {
            printf("%d ", i);
        }
    }
    writeln(" ");
}

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in bc

bc stands for “basic calculator” and was initially written almost half a century ago. As a (programmable) calculator, bc can run mathematical or arithmetic scripts, but it has no string manipulation features. So we use only arithmetical tools here.

define reverse (n) {
    sum = 0
    j = 10 ^ (length(n) - 1)
    while (n > 0) {
        sum += (n % 10) * j
        n = n/10
        j /= 10
    }
    return (sum )
}

define is_reversible(m) {
    sum = m + reverse(m)
    while (sum > 0) {
        k = sum % 10
        if (k % 2 == 0) { 
            return 0 
        }
        sum /= 10
    }
    return 1
}

for (i = 1; i <= 100; i++) {
    # print i, " "
    if (is_reversible(i)) {
        print i, " "
    }
}
quit

Output:

$ bc -q reversible.bc
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72\
81 90

Reversible Numbers in awk

Compared to bc, awk has some limited string manipulation features (such as substr) that we put to good use here. awk also has some regex capabilities, but they’re associated with standard input (e.g. files) reading and did not seem to be usable in our context. So, our program is essentially based on arithmetic loops.

function is_reversible(n) {
    len = length(n)
    m = ""
    for (j = len; j != 0; j--) {
        m = m substr(n, j, 1)
    }
    sum = m + n
    len = length(sum)
    for (k = 1; k <= len; k++) {
        if ((substr(sum, k, 1) % 2) == 0) {
            return 0
        }
    }
    return 1
}

BEGIN {
    for (i = 1; i <= 200; i++) {
        if (is_reversible(i)) {
            printf("%d ", i)
        }
    }
}

Output:

$ awk -f ./reversible.awk
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Python

In Python, we use the features provided by the re regex library, leading to a fairly concise program.

from re import search
pattern = r"[02468]"
for i in range(1, 100):
    tested = str(i + int(str(i)[::-1]))
    if not search(pattern, tested):
        print(i, end=' ')

Output:

$ python3 ./reversible.py
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Ruby

I really like Ruby’s ability to chain method invocations as in sum = n + n.to_s.reverse.to_i, which makes it possible to convert an integer to a string, to revert the string, to convert the resulting string back to an integer and finally finally to add it to another number, all in one short code line. We’ve done similar chained data conversions in Perl, Raku and Julia, but there is a number of mainstream programming languages which can’t do that (mostly because their built-in methods or functions often have side effects and are intrinsically not pure.

def is_reversible(n)
    sum = n + n.to_s.reverse.to_i
    while (sum > 0) 
        k = sum % 10
        if k % 2 == 0 
          return false 
        end
        sum /= 10
    end
    return true
end

for i in 1..100
    if is_reversible(i)
        printf("%d ", i)
    end
end
puts("")

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Scala

Scala also provides the pleasant possibility to chain method invocations (as in var sum = n + n.toString.reverse.toInt). So, our Scala program looks quite similar to our Ruby implementation.

object reversible extends App {
  def is_reversible(n: Int): Boolean = {
    var sum = n + n.toString.reverse.toInt
    while (sum > 0) {
      val k = sum % 10
      if (k % 2 == 0) {
        return false
      }
      sum /= 10
    }
    return true
  }

  for (i <- 1 to 100) {
    if (is_reversible(i)) {
      printf("%d ", i)
    }
  }
  println("")
}

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Ring

for i = 1 to 100
    if is_reversible(i)
        see "" + i + " "
    ok
next

func reverse(num)
    n = "" + num
    rev = ""
    for i = len(n) to 1 step -1
        rev +=  n[i]
    next
    return number(rev)

func is_reversible (m)
    sum = m + reverse(m)
    st = "" + sum
    for i = 1 to (len(st))
        if st[i] % 2 = 0
            return false
        ok
    next
    return true

Output:

$ ring ./reversible.ring
10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in JavaScript

function is_reversible (n) {
    var digits = n.toString().split("")
    let reverse_digits = digits.reverse()
    let reverse_n = parseInt(reverse_digits.join(""));
    var sum = n + reverse_n
    while (sum > 0) {
        let k = sum % 10
        if (k % 2 == 0) { 
          return false 
        }
        sum = Math.floor(sum / 10)
    }
    return true    
}

for (var i = 1; i <= 100; i++) {
    if (is_reversible(i)) {
        process.stdout.write(i + " ")
    } 
}
process.stdout.write(" \n")

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Nim

I tried to use the split function with an empty string as a delimiter, but Nim’s split function apparently does not accept an empty string. Looking for a solution on the Internet, I found on this Stack Overflow page that a Nim string is a sequence of chars, so that a simple cast (e.g. @(intToStr(n)) will split the string into individual chars.

import strutils
import algorithm 

proc is_reversible(n: int): bool =
  # A Nim string is a sequence of chars, so that a cast will 
  # split the string into individual chars
  let rev = parseInt(join(@(intToStr(n)).reversed(), ""))
  var sum = n + rev
  while sum > 0:
    let k = sum mod 10
    if (k mod 2 == 0):
      return false
    sum = (sum / 10).int
  return true    


for i in 1..100:
  if is_reversible(i):
    stdout.write i, " "
echo ""

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Dart

import "dart:io";

void main() {
    for (int i = 0; i <= 100; i++ ) {
        if (is_reversible(i)) {
            stdout.write("$i ");
        }
    }
}

bool is_reversible(n) {
    var rev = int.parse(n.toString().split("").reversed.join(""));
    var digits = (n + rev).toString().split("");
    int len = digits.length;
    for (int i = 0; i < len; i++) {
        if (int.parse(digits[i]) % 2 == 0) {
            return false;
        }
    }
    return true;
}

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Kotlin

fun is_reversible(n: Int): Boolean {
    val sum = n + n.toString().reversed().toInt()
    val sumstr = sum.toString()
    for (i in 1..sumstr.length) {
        if (sumstr[i-1].toInt() % 2 == 0) {
            return false
        }
    }
    return true
}

fun main() {
    for (i in 1..100) {
        if (is_reversible(i)) {
            print("$i ")
        }
    }
    println(" ")
}

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Java

My Java implementation of the reversible numbers task is faithful to Java’s reputation of being very verbose.

public class ReversibleNumbers {

    public static int reverse(int n) {
        String n_str = String.valueOf(n);
        String rev = "";
        char ch;
        for (int i = 0; i < n_str.length(); i++) {
            ch = n_str.charAt(i);   //extracts each character
            rev = ch + rev;         //adds each character in front of the existing string
        }
        return Integer.parseInt(rev);
    }

    public static boolean isReversible(int n) {
        int sum = n + reverse(n);
        char[] digits = String.valueOf(sum).toCharArray();
        for (int i = 0; i < digits.length; i++) {
            if ((digits[i] - '0') % 2 == 0) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {
            if (isReversible(i)) {
                System.out.printf("%d ", i);
            }
        }
        System.out.printf("%s", "\n");
    }
}

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Lua

local function is_reversible(n)
    rev = tonumber(string.reverse(tostring(n)))
    sum = rev + n
    while sum > 0 do
        if sum % 2 == 0 then
            return false
        end
        sum = math.floor(sum / 10)
    end
    return true
end

for i = 1, 100 do
    if is_reversible(i) then
        io.write(i, " ")
    end
end
print("")

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

Reversible Numbers in Go

For some reason, programming languages maintained by groups of dedicated open-source users, such as Raku, Perl, Julia, Nim, JavaScript, Scala, Kotlin, and Lua, have an off-the-shelf reverse function or method, whereas programming languages maintained by very big corporations, such as Java or Go, don’t have it, in spite of their huge financial resources. It appears that the open-source model is more efficient. IT managers should think about it: the best programming languages might not be what they think.

package main

import (
    "fmt"
    "strconv"
)

func reverse(n int) int {
    n_str := strconv.Itoa(n)
    rev := ""
    for _, v := range n_str {
        rev = string(v) + rev
    }
    rev_num, _ := strconv.Atoi(rev)
    return rev_num
}

func is_reversible(n int) bool {
    sum := n + reverse(n)
    sum_str := strconv.Itoa(sum)
    for i := 0; i < len(sum_str); i++ {
        if sum_str[i] % 2 == 0 {
            return false
        }
    }
    return true
}

func main() {
    for i := 1; i <= 100; i++ {
        if is_reversible(i) {
            fmt.Printf("%d ", i)
        }
    }
    fmt.Println("")
}

Output:

10 12 14 16 18 21 23 25 27 30 32 34 36 41 43 45 50 52 54 61 63 70 72 81 90

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 August 14, 2022. And, please, also spread the word about the Perl Weekly Challenge if you can.

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.