G'day IB2017,
The first code statement you presented has problems. You would have seen this had you used strict and warnings. Your code basically has this form:
$ perl -e '%x = { a => 1, b => 2 }' $
With warnings you would have found this problem:
$ perl -e 'use warnings; %x = { a => 1, b => 2 }' Name "main::x" used only once: possible typo at -e line 1. Reference found where even-sized list expected at -e line 1. $
With strict you would have found this problem:
$ perl -e 'use strict; %x = { a => 1, b => 2 }' Global symbol "%x" requires explicit package name (did you forget to d +eclare "my %x"?) at -e line 1. Execution of -e aborted due to compilation errors. $
All your Perl scripts should start with:
use strict; use warnings;
Your next problem seems to be that you think hashes are ordered collections: they are not. If you look at keys, values or each, you'll find the same information:
"Hash entries are returned in an apparently random order. ..."
Read any of those for more information about this.
Using the empty string as a key into %voices will result in an uninitialised value. That's another potential problem; although, you don't show any code that deals with that.
Here's a general solution:
#!/usr/bin/env perl use strict; use warnings; my %all_voices = ( 'Microsoft Hedda Desktop - German' => 3, 'Microsoft Haruka Desktop - Japanese' => 4, 'Microsoft Zira Desktop - English (United States)' => 0, 'Microsoft Hazel Desktop - English (Great Britain)' => 1, 'Microsoft David Desktop - English (United States)' => 2, 'Microsoft Huihui Desktop - Chinese (Simplified)' => 5 ); for my $language (qw{German Japanese French English Chinese}) { my @available_voices = grep /^[^-]+-\s+$language/, keys %all_voice +s; if (@available_voices) { my $first_voice = ( sort { $all_voices{$a} <=> $all_voices{$b} } @available_voices )[0]; printf "%8s : [%d] %s\n", $language, $all_voices{$first_voice}, $first_voice; } else { printf "%8s : No voice found\n", $language; } }
Output:
German : [3] Microsoft Hedda Desktop - German Japanese : [4] Microsoft Haruka Desktop - Japanese French : No voice found English : [0] Microsoft Zira Desktop - English (United States) Chinese : [5] Microsoft Huihui Desktop - Chinese (Simplified)
To remove the English voice with value 0, when there are more than 1 English voices, you can simply add a filter like this:
... if (@available_voices) { if (@available_voices > 1) { @available_voices = grep $all_voices{$_}, @available_voice +s; } ...
Now output is this:
German : [3] Microsoft Hedda Desktop - German Japanese : [4] Microsoft Haruka Desktop - Japanese French : No voice found English : [1] Microsoft Hazel Desktop - English (Great Britain) Chinese : [5] Microsoft Huihui Desktop - Chinese (Simplified)
Finally, you seem (as far as I can tell) to be asking for a "compact" solution. Less code is not necessarily better code: it's often less readable and therefore hard to maintain and potentially error-prone; and, after Perl's optimisations, there's no guarantee it's any more efficient. What exactly are you requirements for this code? Why do you think a "compact" solution would be preferable?
— Ken
In reply to Re: Alternative to sort Hash
by kcott
in thread Alternative to sort Hash
by IB2017
For: | Use: | ||
& | & | ||
< | < | ||
> | > | ||
[ | [ | ||
] | ] |