hmbscully has asked for the wisdom of the Perl Monks concerning the following question:

Here's the scenario:
I receive text files on a regular basis. One file for each country named by XX.txt where 'XX' is the two letter country code. The complete list of the countries I have files for changes regularly. I need an <option> list that corresponds to the available countries.

I have a hash of all the country codes and the country names
A bit of that hash:

%country_names = ( "AF" => "Afghanistan", "AX" => "Aland Islands", "AL" => "Albania", "DZ" => "Algeria", "AS" => "American Samoa", "AD" => "Andorra", "AO" => "Angola", "AI" => "Anguilla", "AQ" => "Antarctica", "AG" => "Antigua And Barbuda", "AR" => "Argentina", "AM" => "Armenia", "AW" => "Aruba", "AU" => "Australia", "AT" => "Austria", "AZ" => "Azerbaijan", "BS" => "Bahamas", "BH" => "Bahrain", "BD" => "Bangladesh", "BB" => "Barbados", );

ect...

What I want to do is this:

opendir(ODIR, "$sr_data/f") || die ("Unable to open directory $sr_data +/f"); @intl_files = grep !/^\./, readdir ODIR; #this line gets rid o +f . and .. closedir ODIR; open(FILE,">$includes_codes_dir/sc_intl_dd.txt"); foreach $file (sort @intl_files) { $file =~ s/\.\w+$//; #remove the extension print FILE "<option value=\"$file\">$country_names{$file +}</option>\n"; } close(FILE);

Which does build me an option list, but the problem is that the option items are in alphabetical order based on the country codes, not the country names. I know it has to do with ordering somewhere along the line, but I'm just having trouble seeing the logic.

Make any sense?
Thanks.


I learn more and more about less and less until eventually I know everything about nothing.

Replies are listed 'Best First'.
Re: hash sorting/alphabetization issue : country postal codes
by grep (Monsignor) on Jul 03, 2007 at 19:40 UTC
    Send sort the hash values not the keys.

    #!/usr/bin/perl use warnings; use strict; my %country_names = ( "AF" => "Afghanistan", "AX" => "Aland Islands", "AL" => "Albania", "DZ" => "Algeria", "AS" => "American Samoa", "AD" => "Andorra", "AO" => "Angola", "AI" => "Anguilla", "AQ" => "Antarctica", "AG" => "Antigua And Barbuda", "AR" => "Argentina", "AM" => "Armenia", "AW" => "Aruba", "AU" => "Australia", "AT" => "Austria", "AZ" => "Azerbaijan", "BS" => "Bahamas", "BH" => "Bahrain", "BD" => "Bangladesh", "BB" => "Barbados", "ZZ" => "AAAAAAA" ); my @sorted_keys = sort { $country_names{$a} cmp $country_names{$b} } k +eys %country_names; print join("\n",@sorted_keys);
      my @sorted_keys = sort { $country_names{$a} cmp $country_names{$b} } k +eys %country_names;

      Considering that in the end you would have sorted VALUES not the keys, above array variable name is rather misleading.

      Correction. Afer grep's reply below, I saw that what was misleading was my claim made above. The array name was reasonable; it was my fault for forgetting that sort sorted the LIST based on result of BLOCK.

        Considering that in the end you would have sorted VALUES not the keys, above array variable name is rather misleading.

        I disagree - @sorted_keys contains SORTED KEYS, sorted by the values.
        But feel free to call it @keys_sorted_by_value if you feel like it.

      The hash is already in alphabetical order by the values. I sorted those first thing.

      I learn more and more about less and less until eventually I know everything about nothing.
        Hashes are not ordered (well in any order you care about). So I don't quite know what you are referring to.

        but the problem is that the option items are in alphabetical order based on the country codes, not the country names.

        Am I not understanding what you meant by that?

Re: hash sorting/alphabetization issue : country postal codes
by rhesa (Vicar) on Jul 03, 2007 at 19:37 UTC
    You can sort by the country name, instead of the code:
    sort { $country_names{$a} cmp $country_names{$b} } @intl_files
    See sort for the details.
Re: hash sorting/alphabetization issue : country postal codes
by FunkyMonk (Bishop) on Jul 03, 2007 at 19:56 UTC
    my %country_names = ( "AF" => "Afghanistan", "AX" => "Aland Islands", "AL" => "Albania", "DZ" => "Algeria", "AS" => "American Samoa", "AD" => "Andorra", ); my @intl_files = <DATA>; chomp @intl_files; # not needed when using opendir/readdir #map removes the ".txt" file suffix #sort compares country names, not codes my @sorted = sort { $country_names{ $a } cmp $country_names{ $b } } map { substr( $_, 0, rindex( $_, '.' ) ) } @intl_files; foreach my $file ( @sorted ) { print "<option value=\"$file\">$country_names{$file}</option>\n"; } __DATA__ AL.txt DZ.txt AS.txt

      Thank you. I understand the problem in my thinking now. I see that I needed to sort previous to the foreach loop rather than in it. I know there are always multiple ways to do things, but this one makes sense to me.

      I learn more and more about less and less until eventually I know everything about nothing.

        I see that I needed to sort previous to the foreach loop rather than in it.

        No, that's not the problem you were having. And there's no problem with putting the sort inside the foreach statement.

        my @codes = map { substr($_, 0, rindex($_, '.')) } @intl_files; foreach my $code ( sort { $country_names{$a} cmp $country_names{$b} } ) { print "<option value=\"$code\">$country_names{$code}</option>\n"; }
Re: hash sorting/alphabetization issue : country postal codes
by snopal (Pilgrim) on Jul 04, 2007 at 00:26 UTC

    If you have arranged for the incoming data to be provided in your preferred order, you can retain that order in the HASH by using Tie::IxHash.

    This avoids the entire sort process. I don't know if this is more efficient than the sort process on this size list.