TASK #2: Spellbound Sorting
You are given an array of integers.
Write a script to return them in alphabetical order, in any language of your choosing. Default language is English.
Sorting by Something Else (An Easy Introduction on Schwartzian Transform)
Sometimes we don't want to sort values directly - we want to sort them by something derived from them.
In this task, we sort numbers by their spelled-out form in a given language (using Lingua::Any::Numbers).
For example (German): 3 2 21 1 becomes: drei zwei einundzwanzig eins
Now we sort those words alphabetically. That order gives us the numbers in this sequence: 3 1 21 2
If we compute the word form inside the sort comparison, Perl may call that function many times.
So the same number might be converted to its word form again and again. That can be inefficient.
Instead, we can:
1. Convert each number to its word once
2. Sort using those words
3. Remove the temporary words afterward
This technique is called the Schwartzian Transform. It simply means:
1. Decorate - attach the computed sort key
2. Sort - sort by that key
3. Undecorate - remove the temporary key
What Happens Internally
If we call:
spellbound_sorting(\@numbers, 'DE');
('DE' -> German language)
then each number is temporarily turned into:
[ word_form , original_number ]
Example:
["drei", 3]
["zwei", 2]
["einundzwanzig", 21]
["eins", 1]
The list is sorted by the word (index = 0), and then we extract the original number (index = 1).
The word is only temporary - it exists purely to control sorting.
My multi-language solution with Schwarzian Transform using only Lingua::Any::Numbers.
#!/usr/bin/perl use strict; use warnings; use Lingua::Any::Numbers qw(num2str); sub spellbound_sorting { my ($numbers, $lang) = @_; my @result; # --------------------------------------------------------------- # The newbie long version: # --------------------------------------------------------------- # Step 1: Decorate # Attach the word form to each number my @decorated; for my $n (@$numbers) { my $word = num2str($n, $lang); push @decorated, [ $word, $n ]; }# Step 2: Sort by the word (element [0]) my @sorted = sort { $a->[0] cmp $b->[0] } @decorated;# Step 3: Undecorate # Extract the original numbers for my $pair (@sorted) { push @result, $pair->[1]; }# --------------------------------------------------------------- The advanced, short solution: # --------------------------------------------------------------- # @result = map { $_->[1] } # sort { $a->[0] cmp $b->[0] } # map { [ num2str($_, $lang), $_ ] } # @$numbers; # --------------------------------------------------------------- return @result; } # Tests my @numbers = (1, 2, 7, 8, 11, 21); my $language;# Example 1 EN $language = "EN"; printf "%s\n", join(", ", spellbound_sorting_alternative(\@numbers, $language));# Output: (8, 11, 1, 7, 21, 2) # Example 2 DE $language = "DE"; printf "%s\n", join(", ", spellbound_sorting_alternative(\@numbers, $language));# Output: (8, 1, 21, 11, 7, 2) # Example 3 NL $language = "NL"; printf "%s\n", join(", ", spellbound_sorting_alternative(\@numbers, $language));# Output: (8, 1, 21, 11, 2, 7) # Example 4 FR $language = "FR"; printf "%s\n", join(", ", spellbound_sorting_alternative(\@numbers, $language));# Output: (2, 8, 11, 7, 1, 21)