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]";
}
I'm not convinced that this is always a better technique, but I have used it sometimes. 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.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:
Hashes are not ordered, but as usual, CPAN offers a solution: Tie::IxHash
From perlfaq4's answer to "How can I make my hash remember the order I put elements into it?"
How can I make my hash remember the order I put elements into it?
Use the Tie::IxHash from CPAN.
Simply:
Another option is David Golden's (@xdg) simple pure perl
Hash::Ordered
module. You gain order but it is slower since the hash becomes an object behind the scenes and you use methods for accessing and modifying hash elements.There are probably benchmarks that can quantify just how much slower the module is than regular hashes but it's a cool way to work with key/value data structures in small scripts and fast enough for me in that sort of application. The documentation mentions several other approaches to ordering a hash as well.