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

Hi Brethren,

Keeping the initial order of insertion into the hash throughout the various map processes of the program. Below illustrates the various stages. I would like the insertion order of %hashA “key” to template the order of %hashB “value”. Then the order of %hashB “key” used to template the order of %hashC “key”. The actual program populates the hashes from a text files. hashA insertion order is descending order by value, hashB, and hashC are in ascending order by key. I had not appreciated that this order would not be retained as perl appears to default sort by key alpha numerically.
It has been suggested that Tie::hash could be an answer, there seems to be many different versions, perhaps someone with experience of Tie::hash could point me in the right direction?

UPDATE
The naming of some of the arrays may have been inappropriate as they may convey that they have been sorted when in fact they have not as pointed out by "limal" also copy and paste error in desired output
Thanks to all in advance.
Gavin
#!usr/bin/perl -W use strict;# forces predeclaration of variables use diagnostics;#diagnostic tools #use Data::Dumper::Simple;#print out contents of variables use porter; # load the porter stemmer module my %hashA = ( 'accord newton second' => 80, 'acceler smaller greater' => 78, 'addit law motion' => 56, 'meant bodi act forc'=> 55, ); foreach my $key(keys %hashA){ #print "$key $hashA{$key}\n"; } my %hashB = (2 => 'addit law motion', 3 => 'accord newton second', 4 => 'meant bodi act forc', 5 => 'acceler smaller greater', ); foreach my $key(keys %hashB){ #print "$key $hashB{$key}\n"; } my @sorted_scores = keys %hashA;#keys from hash A foreach (@sorted_scores){# this gives sorted text #print "$_\n"; } my @sorted_words = map { $hashA{$_} } @sorted_scores;#sorted text foreach (@sorted_words){ #print "$_\n";# this gives the scores sorted out } my %hashC = (2 => "In addition to ", 3 => "According to Newton", 4 => "It also meant that whenever ", 5 => "The acceleration is", ); my (@line_Numbers); my %reversehashB = reverse %hashB; @line_Numbers = map { $reversehashB {$_} }@sorted_scores; foreach (@line_Numbers){ #print "$_\n"; } foreach (@line_Numbers){ print ($_,' ', $hashC{$_}, "\n"); }
The actual out put and desired out put are shown beow
Actual Data Out 4 It also meant that whenever 5 The acceleration is 3 According to Newton 2 In addition to Desired Data Out 3 According to Newton 5 The acceleration is 2 In addition to 4 It also meant that whenever

Replies are listed 'Best First'.
Re: Retaining Insertion order throughout when using “map”
by johngg (Canon) on Apr 13, 2006 at 10:59 UTC
    I think this is what you want. It produces your (updated, I was scratching my head at first :-) desired output. However, you imply that the text files, particularly for %hashA are already sorted. Perhaps you should consider changing the hash for a list so that the order is preserved as you read the data in.

    use strict; use warnings; my %hashA = ( 'accord newton second' => 80, 'acceler smaller greater' => 78, 'addit law motion' => 56, 'meant bodi act forc'=> 55, ); my %hashB = ( 2 => 'addit law motion', 3 => 'accord newton second', 4 => 'meant bodi act forc', 5 => 'acceler smaller greater', ); my %hashC = ( 2 => "In addition to ", 3 => "According to Newton", 4 => "It also meant that whenever ", 5 => "The acceleration is", ); my @insertionOrderA = sort {$hashA{$b} <=> $hashA{$a}} keys %hashA; my %reversehashB = reverse %hashB; foreach (@insertionOrderA) { print "$reversehashB{$_} $hashC{$reversehashB{$_}}\n"; }

    I hope this is of use.

    Cheers,

    JohnGG

Re: Retaining Insertion order throughout when using “map”
by lima1 (Curate) on Apr 13, 2006 at 09:36 UTC
    you want to sort by key of hashB??
    #!usr/bin/perl -W use strict;# forces predeclaration of variables use diagnostics;#diagnostic tools my %hashA = ( 'accord newton second' => 80, 'acceler smaller greater' => 78, 'addit law motion' => 56, 'meant bodi act forc'=> 55, ); my %hashB = (2 => 'addit law motion', 3 => 'accord newton second', 4 => 'meant bodi act forc', 5 => 'acceler smaller greater', ); my %hashC = (2 => "In addition to ", 3 => "According to Newton", 4 => "It also meant that whenever ", 5 => "The acceleration is", ); # this is not a sorted array!!! my @sorted_scores = keys %hashA;#keys from hash A # still not sorted my @sorted_words = map { $hashA{$_} } @sorted_scores;#sorted text my (@line_Numbers); # this sorts the key numerically @line_Numbers = sort {$a <=> $b} keys %hashB; # and prints your desired output foreach (@line_Numbers){ print ($_,' ', $hashC{$_}, "\n"); }
Re: Retaining Insertion order throughout when using “map”
by Limbic~Region (Chancellor) on Apr 13, 2006 at 12:48 UTC
    Gavin,
    Tie::IxHash preserves the order the keys were entered into the hash and has some rudimentary sorting capabilities. I am not sure I quite understand your problem but it sounds like you want to have the order of one hash be dependent on what's in another hash.

    Typically, you would would just roll your own sort routine but it sounds like you want to automagically have the hash come out in the order you want regardless of when and how you modify the hash. At the cost of a little performance and memory, you can use my module Tie::Hash::Sorted to accomplish this.

    Check out the example sort routine. It determines the order of one hash by the value of another hash. If you have a hard time using the module to accomplish what you want, let me know and I will attempt to help further.

    Cheers - L~R