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.
Leave a comment