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

Is it possible to iterate/loop/traverse over two hashes at one go? e.g I have

%hash1 = (..... (key value pair) .... ....); %hash2 = (.... ..... .....); while(......) #iterate both hashes at once { #process something..... }
How should i go about it?

Thank you all for the answers... all above for the answering. I am trying something on bigram techniques. where i have stored bigram count in one hash and word count in other.

What i am trying to do is: From looping those hashes at once, I want to take the value of bigram count and divide with the value of word count.

In case of ordering i used Tie::IxHash module from CPAN. Any better solution to the way i approached my work will be appreciated... Thanks.

Replies are listed 'Best First'.
Re: iterate/traverse Two Hashes at once
by GrandFather (Saint) on Oct 15, 2009 at 07:57 UTC

    Why? Almost certainly you are trying to achieve something which could be done better in some other fashion. Tell us what the bigger problem is and most likely you'll get several solutions that will make your code easier to understand and maintain.


    True laziness is hard work

      Thank you all for the answers... all above for the answering. I am trying something on bigram techniques. where i have stored bigram count in one hash and word count in other.

      What i am trying to do is: From looping those hashes at once, I want to take the value of bigram count and divide with the value of word count.

      In case of ordering i used Tie::IxHash module from CPAN. Any better solution to the way i approached my work will be appreciated... Thanks.

        I still can't figure out what you are trying to achieve, but the following may give you something pertinent to think about:

        use strict; use warnings; my %wordData; my $previousWord; while (<DATA>) { chomp; my @parts = split; for my $part (@parts) { my ($word, $punct) = (lc $part) =~ /(\w+)(.*)/; if ($word) { $wordData{$previousWord}{$word}++ if $previousWord; $wordData{$word}{'!count'}++; } if ($word) { $previousWord = $word; } elsif ($punct) { $previousWord = undef; } } } for my $word (sort keys %wordData) { next if $wordData{$word}{'!count'} < 2; for my $secWord (sort keys %{$wordData{$word}}) { next if $secWord eq '!count'; printf "'%s' is followed by '%s' %.0f%% of the time\n", $word, $secWord, 100.0 * $wordData{$word}{$secWord} / $wordData{$word}{'!co +unt'}; } } __DATA__ Thank you all for the answers... all above for the answering. I am trying something on bigram techniques. where i have stored bigram count in one hash and word count in other. What i am trying to do is: From looping those hashes at once, I want to take the value of bigram count and divide with the value of word count. In case of ordering i used Tie::IxHash module from CPAN. Any better so +lution to the way i approached my work will be appreciated... Thanks.

        Prints:

        'all' is followed by 'above' 50% of the time 'all' is followed by 'for' 50% of the time 'am' is followed by 'trying' 100% of the time 'and' is followed by 'divide' 50% of the time 'and' is followed by 'word' 50% of the time 'bigram' is followed by 'count' 67% of the time 'bigram' is followed by 'techniques' 33% of the time 'count' is followed by 'and' 25% of the time 'count' is followed by 'in' 75% of the time 'for' is followed by 'the' 100% of the time 'from' is followed by 'cpan' 50% of the time 'from' is followed by 'looping' 50% of the time 'i' is followed by 'am' 33% of the time 'i' is followed by 'approached' 17% of the time 'i' is followed by 'have' 17% of the time 'i' is followed by 'used' 17% of the time 'i' is followed by 'want' 17% of the time 'in' is followed by 'case' 33% of the time 'in' is followed by 'one' 33% of the time 'in' is followed by 'other' 33% of the time 'of' is followed by 'bigram' 33% of the time 'of' is followed by 'ordering' 33% of the time 'of' is followed by 'word' 33% of the time 'the' is followed by 'answering' 20% of the time 'the' is followed by 'answers' 20% of the time 'the' is followed by 'value' 40% of the time 'the' is followed by 'way' 20% of the time 'to' is followed by 'do' 33% of the time 'to' is followed by 'take' 33% of the time 'to' is followed by 'the' 33% of the time 'trying' is followed by 'something' 50% of the time 'trying' is followed by 'to' 50% of the time 'value' is followed by 'of' 100% of the time 'word' is followed by 'count' 100% of the time Total words: 0

        True laziness is hard work
Re: iterate/traverse Two Hashes at once
by davido (Cardinal) on Oct 15, 2009 at 07:30 UTC

    Do both hashes contain the same number of keys? If so, easy. If not, you'll have to define what is supposed to happen when you reach the end of one hash, still having a few keys to go in the other hash.

    Assuming you've got the same number of keys in each:

    while( my( $key1, $val1 ) = each( %hash1 ) ) { my( $key2, $val2 ) = each( %hash2 ); # do something with $key1, $key2, $val1, and $val2 }

    Or perhaps both hashes use the same keys, in which case you could....

    while( my( $key, $val1 ) = each( %hash1 ) ) { my( $val2 ) = $hash2{$key}; # Do something with $key, and $val1, $val2. }

    If you require that the iterations occur in a particular order, you'll have to deal with sorting the keys first, and then iterate over your sorted list of keys instead of using each.


    Dave

Re: iterate/traverse Two Hashes at once
by AnomalousMonk (Archbishop) on Oct 15, 2009 at 07:28 UTC
    While it would be possible to loop over two (or more) hashes of equal size at the same time (see example below), the question is why? The 'order' of the key-value pairs of the hashes will not directly correspond to each other in any meaningful way (as shown below) unless, IIRC, the keys of the pairs and the insertion order of the pairs are identical for the hashes – in which case, why not just use a single hash with an array of two (or more) values per key?

    >perl -wMstrict -le "my %ha = qw(ka1 va1 ka2 va2 ka3 va3); my %hb = qw(bk1 bv1 bk2 bv2 bk3 bv3); while (my ($ka, $va) = each %ha and my ($kb, $vb) = each %hb ) { print qq{a: $ka => $va b: $kb => $vb} } " a: ka1 => va1 b: bk3 => bv3 a: ka3 => va3 b: bk2 => bv2 a: ka2 => va2 b: bk1 => bv1
    Maybe you want to extract the sets of keys from two hashes, order the sets relative to each other in some way, and then process the key-value pairs?

Re: iterate/traverse Two Hashes at once
by Marshall (Canon) on Oct 15, 2009 at 07:24 UTC
    Yes, there is a way to extract (key,value) pairs from a hash, but this is used far less often used than just iterating through the key values.

    The order of keys when iterating over all keys in a hash is not defined (unless you read 'em all and then sort 'em or such).

    I am perplexed as to what you would want to do in your proposed loop given that the key,value pairs from %hash1 would have no correlation with %hash2?