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]"; }
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.
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).
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.
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"; }
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"; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With