Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I maintain the order of keys I add to a Perl hash?

Tags:

How can I maintain the order of actual list after counting its occurrence using a hash in the following program? For example, <DATA> are

a b e a c  d  a c d b etc. 

Using hash, i counted the occurrence of each element.

and what i want is:

a  3 b  2 e  1 c  2 d  2 

but the following program shows me otherwise.

my (%count, $line, @array_1, @array_2); while ($line = <DATA>) {     $count{$line}++ if ( $line =~ /\S/ ); } @array_1 = keys(%count); @array_2 = values(%count); for(my $i=0; $i<$#array_1; $i++) {    print "$array_1[$i]\t $array_2[$i]"; } 
like image 561
Cthar Avatar asked Oct 13 '09 07:10

Cthar


People also ask

How do you maintain a hash order in Perl?

Instead of just having the "seen" type of hash, it can store both the count and order noticed. Basically, instead of $count{$line} having the number of times seen, $count{$line}{count} is the times seen and $count{$line}{order} is the order in which it was seen.

Does hashing maintain key order?

Question: Why can't hash tables preserve the order of keys? Answer: There is no fundamental reason why they can't. If you knew enough about your problem, you could design an order preserving hash function (i.e., f(k2)< f(k1) whenever k2< k1).

How do I sort hash keys?

If you want to access a Hash in a sorted manner by key, you need to use an Array as an indexing mechanism as is shown above. This works by using the Emmuerator#sort_by method that is mixed into the Array of keys. #sort_by looks at the value my_hash[key] returns to determine the sorting order.


2 Answers

Hashes are not ordered, but as usual, CPAN offers a solution: Tie::IxHash

use Tie::IxHash; my %count; tie %count, 'Tie::IxHash';  while ($line = <DATA>) { $count{$line}++ if ( $line =~ /\S/ ); }  while( my( $key, $value)= each %count) {     print "$key\t $value";  } 
like image 81
mirod Avatar answered Oct 25 '22 21:10

mirod


Data in a hash table is stored in order of the keys' hash code, which for most purposes is like a random order. You also want to store the order of the first appearance of each key. Here's one way to approach this problem:

my (%count, $line, @display_order); while ($line = <DATA>) {     chomp $line;           # strip the \n off the end of $line     if ($line =~ /\S/) {         if ($count{$line}++ == 0) {             # this is the first time we have seen the key "$line"             push @display_order, $line;         }     } }  # now @display_order holds the keys of %count, in the order of first appearance foreach my $key (@display_order) {     print "$key\t $count{$key}\n"; } 
like image 30
mob Avatar answered Oct 25 '22 22:10

mob