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

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.