I'm trying to rearrange a number into non-English alphabetical order.
my @numDE = < null eins zwei drei vier fünf sechs sieben acht neun >;
# english < zero one two three four five six seven eight nine >;
my %numrank; # The lookup hash: number => its_alphabetical_order
for @numDE.sort.kv -> $k,$v {%numrank{%(@numDE.kv.reverse){"$v"}} = "$k"};
my %temp; # number => reassigned order value
%temp{"$_"}= %numrank{"$_"} for "2378".comb; # 2378 sample input
say %temp.sort(*.values); # this prints:
# (8 => 0 3 => 1 7 => 7 2 => 9) it's in order but unformatted
my %target= %temp.sort(*.values); # Attempt to print it in order
for %target.kv -> $k,$v {print $k}; # that prints in random order
1- How to print the %temp
hash in order?
2- (optional) Is there a way to start using the hash variable without declaring it with my
i.e. as it is in Python?
3- (optional) I've chosen the lookup approach to solve this problem and the resulting code looks a bit convoluted. Could the solution be made shorter using any other approaches?
So there are a couple of things that I'd take a look at, but it does look like you're doing a few extra steps (in the comments you said you've tried a few different things, so I imagine you didn't initial do some many extra).
You've first given yourself the german numbers:
my @numDE = <null eins zwei drei vier fünf sechs sieben acht neun>;
Next, you want to be able to order things based on the German spelling. I'll try to use the method you've approached, but I'll show you a simplier way at the end. Your next step is to effectively cache the sort order of them, and store it into a variable "numrank". Building off of @numDE.sort.kv
, we get
my %numrank;
for @numDE.sort.kv -> $k, $v {
%numrank{$v} = $k;
}
say %numrank;
# {acht => 0, drei => 1, eins => 2, fünf => 3, neun => 4, null => 5, sechs => 6, sieben => 7, vier => 8, zwei => 9}
Okay, not bad. Also note that while the output of %numrank
appears to be ordered, as a hash, it is inherently unordered. It just happens to print keys in alphabetical as a rule and our keys and values are sorted on those lines. Now we just need to use the actual number as the key, rather than the German name instead.
my %numrank;
for @numDE.sort.kv -> $k, $v {
my $id == @numDE.first: $v;
%numrank{$id} = $k;
}
say %numrank;
Oops, we get the same thing. This is because .first
returns the actually object. For its index, we just attach the :k
adverb:
my %numrank;
for @numDE.sort.kv -> $k, $v {
my $id == @numDE.first: $v, :k;
%numrank{$id} = $k;
}
say %numrank;
# {0 => 5, 1 => 2, 2 => 9, 3 => 1, 4 => 8, 5 => 3, 6 => 6, 7 => 7, 8 => 0, 9 => 4}
Perfect, now we can see that the value for 8 (acht) is 0 as it's first, and for 2 (zwei) is 9, as it's last. Note that we could also have used an array here, since our indices are numbers (using @numrank
and then doing @numrank[$id] = $k
)
Now to sort some stuff. In your code you have
%temp{"$_"}= %numrank{"$_"} for "2378".comb; # 2378 sample input
This creates an unordered hash, wherein the name of each key is a digit, and its value is its rank. That's basically what we had above in the first attempt at making %numrank
. But because %temp
is a hash, if you have any two digits that repeat, you'll lose the extras:
%temp{"$_"}= %numrank{"$_"} for "222".comb;
# {2 => 9}
Instead, I think you want to create an array which can allow for ordering:
my @temp = ($_ => %numrank{"$_"}) for "22378".comb;
# ^^ both 2s are preserved
Now you can simply sort on the values:
say @temp.sort: *.values;
You could loop directly on this:
for @temp.sort(*.values) {
print .key;
}
"2378".comb.sort: { @numDE[$^digit] }
# (8 3 7 2) # acht drei seiben zwei
Here we sort the combed digits based on the German text form of each number. @numDE
as the names of the numbers, and $^digit
is an implicit variable that holds the digit (the [ ]
automatically coerces it to a number for us). If you plan on using it regularly, you can actually store the block in a variable, like this:
my &sort-de = sub ($digit) { @numDE[$digit] };
"87446229".comb.sort: &sort-de;
# (8 9 6 7 4 4 2 2)
And as mentioned above, you can do the for loop directly on this, if you want to style it in some other manner:
for "87446229".comb.sort(&sort-de) {
say $_
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With