Click here to get back home

sorting a hash / 2008-06-01

 HomeNewsGroups | Search | About
 comp.lang.perl.misc    Post an article   get this group's latest topics as an RSS feed add this group's latest topics to your My MSN content add this group's latest topics to your My Yahoo content
Subject Author Date
sorting a hash / 2008-06-01 dn.perl@gmail.com 05-30-2008
Posted by dn.perl@gmail.com on May 30, 2008, 3:21 am
Please log in for more thread options

I want to sort a hash. The hash contains a list of cities and their
temperature and I want the 4 cities with max temp. The problem is that
the city-names are one extra level deep with the state-name coming in-
between. I wondered whether I should build the hash differently. A
different format would be: state_city, with the underbar separating
the state and the city.
$hash = 38 ;
instead of
$hash = 38 ;


my %hash = () ;
$hash{San Jose} = 84 ;
$hash{San Fran} = 94 ;
$hash = 38 ;
$hash = 66 ;
$hash = 72 ;
$hash = 96 ;
$hash{Fort Worth} = 62 ;
$hash = 96 ;
$hash = 55 ;
$hash = 55 ;

How do I sort this hash, please?
Thanks in advance.




Posted by John W. Krahn on May 30, 2008, 8:49 am
Please log in for more thread options
dn.perl@gmail.com wrote:
> I want to sort a hash. The hash contains a list of cities and their
> temperature and I want the 4 cities with max temp. The problem is that
> the city-names are one extra level deep with the state-name coming in-
> between. I wondered whether I should build the hash differently. A
> different format would be: state_city, with the underbar separating
> the state and the city.
> $hash = 38 ;
> instead of
> $hash = 38 ;
>
>
> my %hash = () ;
> $hash{San Jose} = 84 ;
> $hash{San Fran} = 94 ;
> $hash = 38 ;
> $hash = 66 ;
> $hash = 72 ;
> $hash = 96 ;
> $hash{Fort Worth} = 62 ;
> $hash = 96 ;
> $hash = 55 ;
> $hash = 55 ;
>
> How do I sort this hash, please?

$ perl -le'
my %hash = (
Calif => {
"San Jose" => { max_temp => 84 },
"San Fran" => { max_temp => 94 },
Cupertino => { max_temp => 38 },
Fremont => { max_temp => 66 },
},
Texas => {
Dallas => { max_temp => 72 },
Austin => { max_temp => 96 },
"Fort Worth" => { max_temp => 62 },
},
Mass => {
Boston => { max_temp => 96 },
Framingham => { max_temp => 55 },
Worcester => { max_temp => 55 },
},
);

print "City: $_->[0] Temperature: $_->[1]"
for (
sort { $b->[ 1 ] <=> $a->[ 1 ] }
map { my $hash = $_; map [ $_, $hash->{ $_ }{ max_temp } ], keys
%$hash }
values %hash
)[ 0 .. 3 ];
'
City: Austin Temperature: 96
City: Boston Temperature: 96
City: San Fran Temperature: 94
City: San Jose Temperature: 84




John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall

Posted by A. Sinan Unur on May 30, 2008, 8:59 am
Please log in for more thread options
4bb7-94dc-f262fc061f37@l64g2000hse.googlegroups.com:

> I want to sort a hash. The hash contains a list of cities and their
> temperature and I want the 4 cities with max temp.

I am going to assume you want the cities with the top four maximum
temperatures.

> The problem is that
> the city-names are one extra level deep with the state-name coming in-
> between. I wondered whether I should build the hash differently. A
> different format would be: state_city, with the underbar separating
> the state and the city.
> $hash = 38 ;
> instead of
> $hash = 38 ;

First, note that it might make your life easier later to use standard
abbreviations such as CA for California, TX for Texas. If you need to
also present longer names, you could use a lookup table.

> $hash{San Fran} = 94 ;

Similarly, I would use the actual identifier for the reporting
temperature measurement station instead of a cutesy abbreviation of the
city name. You could use a lookup table to map station identifiers to
city names.

It is also not nice to post code that you have not tested at all:

C:\Temp> cat s.pl
#!/usr/bin/perl

use strict;
use warnings;

my %hash = () ;
$hash{San Jose} = 84 ;
$hash{San Fran} = 94 ;
$hash = 38 ;
$hash = 66 ;
$hash = 72 ;
$hash = 96 ;
$hash{Fort Worth} = 62 ;
$hash = 96 ;
$hash = 55 ;
$hash = 55 ;


C:\Temp> s
Can't locate object method "San" via package "Jose" (perhaps you forgot
to load "Jose"?) at C:\Temp\s.pl line 7.

You need to quote keys that do not consist solely of \w characters.

Please read the posting guidelines for this group and follow them.

Second, the data structure is dictated by the problem at hand usually. I
think it is futile to venture whether a different data structure would
be more appropriate using only the information you give in this post. In
general, I do not favor using composite hash keys unless there is a
complelling reason to do so.

However, assuming you are only storing a single attribute for each city,
then I would recommend:

my %maxtemp;

$maxtemp->{San Jose} = 94;

etc.

> How do I sort this hash, please?

By definition, a hash table is unsorted. You may present the contents in
a certain order, but the data structure itself remains unaffected by
that presentational transformation.

That said, a full blown sort seems to be unnecessary here. You said all
you want are the four cities with the highest maximum tempreatures. On
the other hand, simply sorting and picking up the four elements at the
top has a certain appeal as well. Both of these might fail according to
some criteria if there are ties. How do you handle ties?

The following code will find the highest four temperatures and list the
cities with those temperatures. It does not handle the case where there
are fewer than four distinct temperatures in the whole data set.


#!/usr/bin/perl

use strict;
use warnings;

my %maxtemp = () ;
$maxtemp->{'San Jose'} = 84;
$maxtemp->{'San Fran'} = 94;
$maxtemp-> = 38;
$maxtemp-> = 66;
$maxtemp-> = 72;
$maxtemp-> = 96;
$maxtemp->{'Fort Worth'} = 62;
$maxtemp-> = 96;
$maxtemp-> = 55;
$maxtemp-> = 55;

my %cities_by_temp;

for my $state ( keys %maxtemp ) {
for my $city ( keys %{ $maxtemp } ) {
my $temp = $maxtemp->;
push @{ $cities_by_temp }, "$city, $state";
}
}

my @highest = (sort { $b <=> $a } keys %cities_by_temp)[0 .. 3];

for my $temp ( @highest ) {
print "$temp\t", join("\n\t", @} ), "\n";
}

__END__





--
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/

Posted by dn.perl@gmail.com on June 7, 2008, 1:30 am
Please log in for more thread options
On May 30, 5:59 am, "A. Sinan Unur" wrote:
>
> How do you handle ties?
>

I was asked to list cities with the top 4 maximum temperature, and
there was no word on how to handle ties. But that is a trivial part of
the problem. I suggested a solution (which the client was fine with)
that if a tie makes the list extend beyond 4 where city #4 has temp >
90, list all elements of the tie. If the city #4 has temp <= 90, break
the tie at 4.

Thus :
Austin 105
Miami 93
New York 91
Phoenix 91
Boston 91
Framingham 91 (6 cities listed)
Not listed ===> Dallas 88.

But :
Austin 105
Miami 93
New York 88
Phoenix 88
Not listed ==> Boston 88. Stop after first 4 entries.
Not listed ==> Chicago 88
Not listed ==> Seattle 82


Posted by Gunnar Hjalmarsson on May 30, 2008, 9:11 am
Please log in for more thread options
dn.perl@gmail.com wrote:
> I want to sort a hash. The hash contains a list of cities and their
> temperature

Well, I'd rather say it contains three hash references.

This is one sensible way to sort that data structure:

foreach my $state ( sort keys %hash ) {
print "State: $state\n";
foreach my $city ( sort { $a cmp $b } keys %{ $hash } ) {
print "$city = $hash\n";
}
print "\n";
}

> and I want the 4 cities with max temp.

I'm not sure what you mean by that. Please clarify what's the desired
output.

> The problem is that
> the city-names are one extra level deep with the state-name coming in-
> between. I wondered whether I should build the hash differently.

Probably. This is one idea:

my %hash = (
'San Jose' => {
state => 'Calif',
max_temp => 84,
},
'San Fran' => {
state => 'Calif',
max_temp => 94,
},
);

> my %hash = () ;
> $hash{San Jose} = 84 ;
---------------^^^^^^^^
Hash keys with spaces need to be quoted.

$hash{'San Jose'} = 84 ;

> $hash{San Fran} = 94 ;
> $hash = 38 ;
> $hash = 66 ;
> $hash = 72 ;
> $hash = 96 ;
> $hash{Fort Worth} = 62 ;
> $hash = 96 ;
> $hash = 55 ;
> $hash = 55 ;

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl

Similar ThreadsPosted
Sorting a hash containing a hash of hashes December 14, 2005, 2:29 pm
Hash Sorting June 14, 2005, 2:49 pm
Sorting Hash by Value and Key May 17, 2007, 9:57 am
Sorting on sub-hash values June 23, 2005, 11:30 am
Sorting AofH over hash key(s)... October 30, 2007, 4:40 pm
Nested sorting of a hash December 6, 2007, 6:23 am
warnings on sorting hash of hashes January 5, 2005, 11:53 pm
sorting data - hash vs. list September 11, 2005, 4:41 pm
Sorting array of hash references October 26, 2006, 6:21 am
Sorting "string" numerical keys from a hash. September 5, 2004, 2:47 pm

Our other projects:

Art Dolls, Fairies and Mermaids - Sunnyfaces.net

Roy's Linux, Programming and Search Engines messages

1-Script XML SitemapXML Sitemap