Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Finding Recurring Elements in HoHoA

by neversaint (Deacon)
on Aug 04, 2005 at 09:12 UTC ( #480731=perlquestion: print w/replies, xml ) Need Help??

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

Dear Masters,
Given this hash I want to identify animal that:
1.Occur more than once within the states, AND
2.Occur in more than one states.
In this case the animal is HIPPO.
my %bighash = ( 'Arizona'=> { 'ZOO_1' => [ '5','HIPPO', ['some arr'],['some arr']], 'ZOO_2' => [ '10','HIPPO',['some arr'],['some arr']], 'ZOO_3' => [ '2', 'PUMA', ['some arr'],['some arr']], 'ZOO_5' => [ '1', 'PUMA', ['some arr'],['some arr']], }, 'Indiana' => { 'ZOO_9' => [ '25', 'ZEBRA', ['some arr'],['some arr']], 'ZOO_5' => [ '13', 'MONKEY',['some arr'],['some arr']], 'ZOO_6' => [ '23', 'ZEBRA', ['some arr'],['some arr']], }, 'Nevada' => { 'ZOO_3' => [ '3', 'HIPPO', ['some arr'],['some arr']], 'ZOO_7' => [ '11', 'HIPPO',['some arr'],['some arr']], 'ZOO_4' => [ '21', 'LION', ['some arr'],['some arr']], 'ZOO_12' => [ '13', 'MONKEY',['some arr'],['some arr']], }, );
Such that in the end it simply have:
Arizona ZOO: ZOO_1 ANIMAL: HIPPO ZOO: ZOO_2 ANIMAL: HIPPO NEVADA ZOO: ZOO_3 ANIMAL: HIPPO ZOO: ZOO_7 ANIMAL: HIPPO
What's wrong with my code below such that it doesn't gives the answers correctly?
print Dumper \%bighash ; foreach my $states ( sort keys %bighash ) { print "$states\n"; foreach my $zoo ( keys %{$bighash{$states}} ) { my $cur = $bighash{$states}{$zoo}->[1]; my $count = 0; foreach my $nzoo ( keys %{$bighash{$states}} ) { my $nxt = $bighash{$states}{$nzoo}->[1]; if ( $cur eq $nxt ) { $count++; if ( $count > 1 ) { print "ZOO: $zoo ANIMAL: $nxt\n"; } } } # ----- end foreach ----- } # ----- end foreach ----- } # ----- end foreach -----


---
neversaint and everlastingly indebted.......

Replies are listed 'Best First'.
Re: Finding Recurring Elements in HoHoA
by polettix (Vicar) on Aug 04, 2005 at 10:09 UTC
    I think that you cannot solve this problem easily working incrementally as you do. Moreover, your specs are a bit unclean, because you're asking for animal names, but you want to print out more info. What if HIPPO appears also in Indiana, but only one time? Would Indiana be printed (because it contains an animal that matches the specs) or wouldn't it (because the animal appears only one time)?

    I usually find it cleaner to transform the data in something that is straightforward to analyse later, possibly using more logic passes. In this case, I see two distinct problems:

    • detection: you have to tell which animals match your rules
    • presentation: you have to print the way you like.
    For the detection part, I'd use a hash of hashes in which the first index is the animal name, and the second is the name of the state. The elements would be the names of the zoos:
    use strict; use warnings; use Data::Dumper; my %bighash = ( 'Arizona'=> { 'ZOO_1' => [ '5','HIPPO', ['some arr'],['some arr']], 'ZOO_2' => [ '10','HIPPO',['some arr'],['some arr']], 'ZOO_3' => [ '2', 'PUMA', ['some arr'],['some arr']], 'ZOO_5' => [ '1', 'PUMA', ['some arr'],['some arr']], }, 'Indiana' => { 'ZOO_9' => [ '25', 'ZEBRA', ['some arr'],['some arr']], 'ZOO_5' => [ '13', 'MONKEY',['some arr'],['some arr']], 'ZOO_6' => [ '23', 'ZEBRA', ['some arr'],['some arr']], }, 'Nevada' => { 'ZOO_3' => [ '3', 'HIPPO', ['some arr'],['some arr']], 'ZOO_7' => [ '11', 'HIPPO',['some arr'],['some arr']], 'ZOO_4' => [ '21', 'LION', ['some arr'],['some arr']], 'ZOO_12' => [ '13', 'MONKEY',['some arr'],['some arr']], }, ); my %animals; foreach my $state (keys %bighash) { foreach my $zoo (keys %{$bighash{$state}}) { my $animal = $bighash{$state}{$zoo}[1]; push @{$animals{$animal}{$state}}, $zoo; } } # Now traverse %animals to find "pervasive" animals my %pervasive_animals; foreach my $animal (keys %animals) { foreach my $state (keys %{$animals{$animal}}) { if (@{$animals{$animal}{$state}} > 1) { # Occurs in more zoos $pervasive_animals{$animal}{$state} = $animals{$animal}{$stat +e}; } } # Now verify the state requirement delete $pervasive_animals{$animal} unless keys %{$pervasive_animals{$animal}} > 1; } print Dumper(\%pervasive_animals); __END__ $VAR1 = { 'HIPPO' => { 'Nevada' => [ 'ZOO_7', 'ZOO_3' ], 'Arizona' => [ 'ZOO_1', 'ZOO_2' ] } };
    Now %pervasive_animals holds all the animals that match the spec, together with the states and zoos where you can find them.

    The presentation part is left as an exercise :) BTW, you have an error in the input data, one of the HIPPOs contains a final "0" (zero digit) instead of the big "O" (letter).

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
Re: Finding Recurring Elements in HoHoA
by (anonymized user) (Curate) on Aug 04, 2005 at 10:03 UTC
    The '$cur eq $nxt' test will always compare an entry with itself at some time during each execution of the loop, thus finding a false duplicate. However, the print is driven by $count, which scopes within a state, which has the effect also of hiding the duplicate test. In a correct solution, duplicates need to be detected across states and the print needs to address a uniquified list of everything that was found in a successful duplicate test.

    Update: As the other replies suggest - this uniquify idea is best implemented in a summary hash that matches your output.

    One world, one people

Re: Finding Recurring Elements in HoHoA
by Taulmarill (Deacon) on Aug 04, 2005 at 09:45 UTC
    i would use a different approach and sort the found animals in another hash which is structured in a way, that makes printing easyer
    my %animals; for my $state ( keys %bighash ) { for my $zoo ( keys %{ $bighash{$state} } ) { $animals{ $bighash{$state}{$zoo}->[1] }->[0]->{$state}->{$zoo} +++; $animals{ $bighash{$state}{$zoo}->[1] }->[1]++; } } for my $animal ( keys %animals ) { next unless $animals{$animal}->[1] > 1; for my $state ( keys %{ $animals{$animal}->[0] } ) { print "$state\n"; for my $zoo ( keys %{ $animals{$animal}->[0]->{$state} } ) { print "ZOO: $zoo ANIMAL: $animal\n"; } print "\n"; } }
      Your solution does not take into account that the animal must "1.Occur more than once within the states, AND 2.Occur in more than one states.", it only checks that an animal occurs at least two times in the whole bighash.

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.
        i left that as an excersise to the reader ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://480731]
Approved by polettix
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2020-06-07 06:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you really want to know if there is extraterrestrial life?



    Results (42 votes). Check out past polls.

    Notices?