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

hi,

i need help with this one :) the point of this problem is that i'm looking for a way to retrace my steps. let say i have this hash that is only declared & initialized like this:

use strict; use Data::Dumper; my %hash; %hash = (key1 => [1], key2 => [1], key3 => [1]);
also let say this hash is a class variable. and thet every time the class method is called the result of its calculation is pushed into a hash, like this:
push(@{$hash{key2}},4); push(@{$hash{key3}},8); push(@{$hash{key1}},7); push(@{$hash{key2}},9); $hash{key4} = [8]; push(@{$hash{key2}},9); push(@{$hash{key3}},2);
so now i'm looking for a procedure to retrace the exact order in which i inputed the last data into my hash. in other words i would like to receive data in following order:
foreach (hash key){ my $last_one = pop(@{$hash{$_}}); print "$_ $last_one \n"; } so that rtesult is going to be: key3 2 key2 9 key4 8 key1 7 and in next iteration : key2 9 key3 8 key1 1
i don't know if you understand what am i aiming for. the data structure has to be in the hash form and only thing that interests me how to retrieve those data from that hash in revers order they were entered into the hash.

any ideas??? (i'm not looking for the actual code but just an idea :))

thank you

Replies are listed 'Best First'.
Re: retrieving hash keys
by CountZero (Bishop) on May 09, 2009 at 11:58 UTC
    As your hash does not keep any data about the sequence of adding new values, there is no way you can retrace your steps.

    If you want to accomplish that, either you must keep a journal file with your steps or you must use a different data structure, which keeps next to each element a sequence number on basis of which you can later retrieve and sort your steps.

    Tie::HashHistory goes somewhat along that way, but I'm not sure if it can look into the anonymous arrays which are the values of your hash. At first glance it will only look one level deep.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: retrieving hash keys
by jethro (Monsignor) on May 09, 2009 at 13:49 UTC

    If you can avoid that anyone writes to your hash directly instead of using the accessors of the class then it is relatively easy. You can either use a log or have the hash store not only the value but a serial number/sequence value (concatenated or in a HoH or HoA structure).

    If not, you have to use 'tie' to add that functionality, i.e. tie that hash to methods that use an underlying data structure as suggested above, a log or a HashOfHashes with sequence values

    Naturally you can't access the sequence numbers from the hash but from additional methods that access the underlying data structure

    See 'perldoc -f tie' for more information

Re: retrieving hash keys
by Bloodnok (Vicar) on May 10, 2009 at 00:32 UTC
    ...sounds like Tie::IxHash might just be your closest friend.

    A user level that continues to overstate my experience :-))
Re: retrieving hash keys
by ig (Vicar) on May 09, 2009 at 22:06 UTC

    You might find Data::Pairs useful.

    In addition to your hash, you could record the keys and values in an array, then reverse the array to retrieve the reverse of the entry order. This is just another implementation of a log or journal, as suggested previously.

    As it appears from your example that your sets of data may be interleaved, unrolling them is not as simple as merely reversing the log/journal. You might do something like the following:

    use strict; use warnings; use Data::Dumper; my %hash = (key1 => [1], key2 => [1], key3 => [1]); my @array = ( [ key1 => 1 ], [ key2 => 1 ], [ key3 => 1 ], ); my %keys = ( key1 => 1, key2 => 1, key3 => 1, ); foreach my $result ( [ key2 => 4 ], [ key3 => 8 ], [ key1 => 7 ], [ key2 => 9 ], [ key4 => 8 ], [ key2 => 9 ], [ key3 => 2 ], ) { my ($key, $value) = @$result; push(@{$hash{$key}},$value); push(@array, $result ); $keys{$key}++; } my $nkeys = scalar(keys %keys); while(@array) { my @set; my %set; for( my $i = $#array; $i >= 0; $i-- ) { my ($key, $value) = @{ $array[$i] }; unless($set{$key}) { push(@set, splice(@array, $i, 1)); $set{$key} = $value; } last if( @set == $nkeys ); } foreach my $entry (@set) { print "@$entry\n"; } print "\n"; } __END__ key3 2 key2 9 key4 8 key1 7 key2 9 key3 8 key1 1 key2 4 key3 1 key2 1