perl logo Perl logo (Thanks to Olaf Alders)

The weekly challenge 362 - Task 2: Spellbound Sorting

  1 #!/usr/bin/env perl
  2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-362/#TASK2
  3 #
  4 # Task 2: Spellbound Sorting
  5 # ==========================
  6 #
  7 # You are given an array of integers.
  8 #
  9 # Write a script to return them in alphabetical order, in any language of your
 10 # choosing. Default language is English.
 11 #
 12 ## Example 1
 13 ##
 14 ## Input: (6, 7, 8, 9 ,10)
 15 ## Output: (8, 9, 7, 6, 10)
 16 ##
 17 ## eight, nine, seven, six, ten
 18 #
 19 #
 20 ## Example 2
 21 ##
 22 ## Input: (-3, 0, 1000, 99)
 23 ## Output: (-3, 99, 1000, 0)
 24 ##
 25 ## minus three, ninety-nine, one thousand, zero
 26 #
 27 #
 28 ## Example 3
 29 ##
 30 ## Input: (1, 2, 3, 4, 5)
 31 ##
 32 ## Output: (5, 2, 4, 3, 1) for French language
 33 ## cinq, deux, quatre, trois, un
 34 ##
 35 ## Output: (5, 4, 1, 3, 2) for English language
 36 ## five, four, one, three, two
 37 #
 38 #
 39 ## Example 4
 40 ##
 41 ## Input: (0, -1, -2, -3, -4)
 42 ## Output: (-4, -1, -3, -2, 0)
 43 ##
 44 ## minus four, minus one, minus three, minus two, zero
 45 #
 46 #
 47 ## Example 5
 48 ##
 49 ## Input: (100, 101, 102)
 50 ## Output: (100, 101, 102)
 51 ##
 52 ## one hundred, one hundred and one, one hundred and two
 53 #
 54 ############################################################
 55 ##
 56 ## discussion
 57 ##
 58 ############################################################
 59 #
 60 # The most tricky part here is to get the spelling of the numbers
 61 # right. For this, we write a function for each language which returns
 62 # the written representation of the number (implemented below are
 63 # English and French, supporting numbers up until 9999).
 64 # Then we just need to sort by the result of this function.
 65 # The real magic happens inside those functions turning numbers into
 66 # their string representations as that's a long list of checking
 67 # various cases.
 68 
 69 use v5.36;
 70 
 71 spellbound_sorting(6, 7, 8, 9 ,10);
 72 spellbound_sorting(-3, 0, 1000, 99);
 73 spellbound_sorting(1, 2, 3, 4, 5);
 74 spellbound_sorting(0, -1, -2, -3, -4);
 75 spellbound_sorting(100, 101, 102);
 76 
 77 sub spellbound_sorting(@ints) {
 78     say "Input: (" . join(", ", @ints) . ")";
 79     say "Output for English: (" .
 80        join(", ", sort { number_to_english($a) cmp number_to_english($b) } @ints) . ")";
 81     say "Output for French: (" .
 82        join(", ", sort { number_to_french($a) cmp number_to_french($b) } @ints) . ")";
 83 }
 84 
 85 sub number_to_english($number) {
 86     return "minus " . number_to_english(-$number) if $number < 0;
 87     my @numbers = ("zero", "one", "two", "three", "four", "five",
 88         "six", "seven", "eight", "nine", "ten", "eleven", "twelve",
 89         "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
 90         "eighteen", "nineteen", "twenty");
 91     return $numbers[$number] if $number < 21;
 92     my $tens = { 20 => "twenty", 30 => "thirty", 40 => "forty",
 93         50 => "fifty", 60 => "sixty", 70 => "seventy",
 94         80 => "eighty", 90 => "ninety" };
 95     if(20 < $number && $number < 100) {
 96         my $t = 10 * int($number / 10);
 97         if($number % 10) {
 98             return $tens->{$t} . "-" . $numbers[$number % 10];
 99         } else {
100             return $tens->{$t};
101         }
102     }
103     if($number < 1000) {
104         my $h = int($number / 100);
105         return $numbers[$h] . " hundred " . number_to_english($number % 100) if $number % 100;
106         return $numbers[$h] . " hundred";
107     }
108     my $t = int($number / 1000);
109     return $numbers[$t] . " thousand " . number_to_english($number % 1000) if $number % 1000;
110     return $numbers[$t] . " thousand";
111 }
112 
113 sub number_to_french($number) {
114     return "moins " . number_to_french(-$number) if $number < 0;
115     my @numbers = ("zéro", "un", "deux", "trois", "quatre", "cinq",
116         "six", "sept", "huit", "neuf", "dix", "onze", "douze",
117         "treize", "quatorze", "quinze", "seize", "dix-sept",
118         "dix-huit", "dix-neuf", "vingt");
119     return $numbers[$number] if $number < 21;
120     my $tens = { 20 => "vingt", 30 => "trente", 40 => "quarante",
121         50 => "cinquante", 60 => "soixante", 80 => "quatre-vingts" };
122     if(20 < $number && $number < 70) {
123         my $t = 10 * int($number / 10);
124         if($number % 10) {
125             return $tens->{$t} . " et un" if $number % 10 == 1;
126             return $tens->{$t} . "-" . $numbers[$number % 10];
127         } else {
128             return $tens->{$t};
129         }
130     }
131     if($number < 80) {
132         return "soixante-dix" if $number == 70;
133         return "soixante et onze" if $number == 71;
134         return "soixante-" . $numbers[$number - 60];
135     }
136     if($number < 100) {
137         return "quatre-vingts" if $number == 80;
138         return "quatre-vingt-" . $numbers[$number - 80];
139     }
140     if($number < 200) {
141         return "cent" if $number == 100;
142         return "cent " . number_to_french($number % 100);
143     }
144     if($number < 1000) {
145         my $h = int($number / 100);
146         return $numbers[$h] . " cent " . number_to_french($number % 100) if $number % 100;
147         return $numbers[$h] . " cent";
148     }
149     my $t = int($number / 1000);
150     if($number < 2000) {
151         return "mille " . number_to_french($number % 1000) if $number % 1000;
152         return "mille";
153     } else {
154         return $numbers[$t] . " mille " . number_to_french($number % 1000) if $number % 1000;
155         return $numbers[$t] . " mille";
156     }
157 }