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

I have a %hash that when printed with DUMPER gives something like :
'555549' => [ '172193', '19601', '19602', '3252', '3665', '8959', '4758', '14835', '16718' ], '560834' => [ '172193', '19601', '19602', '3252', '3665', '8959', '4758', '14835', '16718' ],

There are more though. So i will like to be able to read the first 2 key values in the hash, compare them(this i know how to) then insert the difference somewhere(i know how). Then take the 3rd key(present) and compare with the 2nd one(previous).Do the same until the whole keys have been iterated through. So its just pick previous and present,do my thing, move to next etc. The truth is, i don't know how to access each key the way i explained in style of previous/present. Any algorithms,tips,answers will be useful.</code>

This is how i populated the %hash:

my %result; while ( my $rec = $data->fetchrow_hashref ) { push @{ $result{ $rec->{"ID"} } }, $rec->{"item"}; }

Replies are listed 'Best First'.
Re: compare previous and present hash key values
by choroba (Cardinal) on Jan 11, 2014 at 15:00 UTC
    Hash keys are not ordered. What do you mean by "first 2 keys"?
    my @keys = sort your_sorting_routine keys %result; for my $i (0 .. $#keys - 1) { compare($result{ $keys[$i] }, $result{ $keys[$i + 1] }); }

    Or, if you do not want to store the keys in an array, but retrieve them one by one:

    my $previous = retrieve_key(); while (defined (my $next = retrieve_key())) { compare($result{$previous}, $result{$next}); $previous = $next; }
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      It's neighboring keys actually. So to begin, i will start with the first key in the hash and compare with the second, then the second with the third etc. I tried your code but it says undefined subroutine retrieve_key.

      Best regards.
        Yes, you have to write your_sorting_routine or retrieve_key yourself. In Perl, there is no "neighbouring" hash key - hash keys have no defined order, as has been already pointed out.
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: compare previous and present hash key values
by LanX (Saint) on Jan 11, 2014 at 15:00 UTC
    The way I understand the question, you are needing to compare all pairs of neighboring keys.

    The problem is that hashes do not preserve order, you need an array @result for that or you have to store the order of keys separately in an array @order.¹

    that's one way to go pairwise:

    DB<120> @order=1..5 => (1, 2, 3, 4, 5) DB<121> $last= $order[0] => 1 DB<122> for $cur (@order[1..$#order]) { print "$last,$cur\t"; $last =$cur; } => "" 1,2 2,3 3,4 4,5

    edit

    For completeness, a shorter but trickier way, using reduce:

    DB<126> use List::Util qw/reduce/ DB<127> reduce { print "$a,$b\n"; $b } @order 1,2 2,3 3,4 4,5

    HTH! =)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    update

    ¹) e.g.

    while ( my $rec = $data->fetchrow_hashref ) { push @{ $result{ $rec->{"ID"} } }, $rec->{"item"}; push @order, $rec->{ID}; }

      I just converted the hash into an array sorted

      using:
      my @array = map { $result{$_} } sort { $a<=>$b } keys %result;

      Since it's now an array, how may i proceed ?

      This is the print of the array sorted without keys though:

      $VAR1 = [ [ '172193', '19601', '14835', '16718' ], [ '172193', '19601', '14835', '16718' ], [ '172193', '19601', '14835', '16718' ], [ '172193', '19601', '14835', '16718' ], continues....

      for now they all look the same but as it progresses there are differences

      I don't understand your code well, also the lines of code added to your code confuses.

        OK once again...

        ( supposing that the numerical order of IDs is not the compare order you want, but that you still need the ID for further evaluation)

        do this to keep record of the order of the keys

        my %order; while ( my $rec = $data->fetchrow_hashref ) { push @{ $result{ $rec->{"ID"} } }, $rec->{"item"}; push @order, $rec->{ID}; # read order }

        and do this to compare the neighboring keys

        my $last = $order[0]; # first key for my $cur ( @order[1..$#order] ) { # following key +s compare($last,$cur); $last = $cur; # keep current +as last }

        plz note: compare() is a sub you have to provide, you said "this i know how to".

        Within compare you can access the values of the hash '%result' with the neighboring keys '$last' and '$cur'.

        like

        sub compare { my ($previous,$present) = @_; ... }

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: compare previous and present hash key values
by NetWallah (Canon) on Jan 11, 2014 at 15:07 UTC
    Are you trying to compare a list of ITEMS associated with each ID ?

    How complex is the "compare" ? Is it just checking if the item exists in the values for the other ID ?

    These types of queries are usually much more efficient and readable when done in SQL. using something like :

    SELECT item from mytable WHERE ID = '555549' AND item NOT IN (SELECT item from mytable where ID='560834');
    Of course, you can use perl to build the query and subquery.

    Update:

    If you really want to examine CURRENT, PREVIOUS and NEXT items in an array, consider using Array::Iterator::BiDirectional.

            If your eyes hurt after you drink coffee, you have to take the spoon out of the cup.
                  -Norm Crosby

      Thanks for your reply. The compare will be something like :

      my @a = ( 100, 112,123, 333, 500 ); my @b = ( 100, 333, 500 ); my %b = map { $_ => 1 } @b; my @missing = grep { !$b{$_} } @a;

      Which should give, in that case "112" and "123"

        Re-posting, in case you did not notice my update to my previous post:

        If you really want to examine CURRENT, PREVIOUS and NEXT items in an array, consider using Array::Iterator::BiDirectional.

        However - the need for that is not clear, from the information you have provided so far.

        If you post pseudo-code (even if it does not work/compile) of what you are trying to do - we may provide better alternatives.

                If your eyes hurt after you drink coffee, you have to take the spoon out of the cup.
                      -Norm Crosby