Search code examples
perlloopshashfor-loophash-reference

Perl Creating hash reference and looping through one element from each branch at a time


As a beginner I have what I think is a rather complicated problem I am hoping someone could help with.

I have the following text file (tab delminated)...

FILE1.txt

Dog     Big     
Dog     Medium     
Dog     Small     
Rabbit     Huge     
Rabbit     Tiny     
Rabbit     Middle    
Donkey     Massive    
Donkey     Little   
Donkey     Gigantic

I need to read FILE1.txt into a hash reference to get something like the following... (using Data::Dumper)

$VAR1 = {
        'Dog' => {
                 'Big',
                 'Medium',
                 'Small'
                 },
        'Rabbit  => {
                    'Huge',
                    'Tiny',
                    'Middle'
                    },
        'Donkey  => {
                    'Massive',
                    'Little',
                    'Gigantic'
                    },                               
        };

The problem I am having:

I then need to loop through each branch of the hash reference one at a time, I will use the value from the hash reference to check if this matches my keyword, if so it will then return it's corresponding key.... for example...

What I need it to do:

my $keyword == "Little";

Dog->Big 
if 'Big' matches my keyword then return $found = Dog
else go to the next branch
Rabbit->Huge
if 'Huge' matches my keyword then return $found = Rabbit
else go to the next branch
Donkey->Massive
if 'Massive' matches my keyword then return $found = Donkey
else go to the next branch (which is Dog again, but the second element this time)
Dog->Medium
if 'Medium' matches my keyword then return $found = Dog
else go to the next branch
Rabbit->Tiny
if 'Tiny' matches my keyword then return $found = Rabbit
else go the the next branch
Donkey->Little
if 'Little' matches my keyword then return $found = Donkey

..... and so on until the keyword is found or we reach the end of the hash reference

This is the kind of thing I am trying to achieve but don't know how to go about doing this, or whether a hash reference is the best way to do this, or if it can even be done with a hash/hash reference?

your help with this is much appreciated, thanks


Solution

  • Choosing proper data structure is often key step to the solution, but first of all you should define what you are trying achieve. What is overall goal? For example I have this data file and in mine application/program I need frequently ask for this information. It is crucial to ask proper question because for example if you don't need ask frequently for keyword it doesn't make sense creating hash at all.

     perl -anE'say $F[0] if $F[1] eq "Little"' FILE1.txt
    

    Yes it is that simple. Look in perlrun manpage for switches and what they mean and how to do same thing in bigger application.

    If you need frequently ask for this question you should arrange your data in way which helps you and not in way you have to battle with.

    use strict;
    use warnings;
    use feature qw(say);
    use autodie;
    
    open my $f, '<', 'FILE1.txt';
    my %h;
    while(<$f>) {
        chomp;
        my ($animal, $keyword) = split' ';
        $h{$keyword} = $animal unless exists $h{$keyword};
    }
    
    close $f;
    
    for my $keyword (qw(Little Awkward Small Tiny)) {
        say $h{$keyword} ? "$keyword $h{$keyword}" : "keyword $keyword not found";
    }
    

    But if you still insist you want to traverse hash you can do it but you has been warned.

    open my $f, '<', 'FILE1.txt';
    my %h;
    while (<$f>) {
        chomp;
        my ( $animal, $keyword ) = split ' ';
        push @{ $h{$animal} }, $keyword;
    }
    
    close $f;
    
    KEYWORD:
    for my $keyword (qw(Little Awkward Small Tiny)) {
        for my $animal (keys %h) {
            for my $k (@{$h{$animal}}) {
                if($k eq $keyword) {
                    say "$keyword $animal";
                    next KEYWORD;
                }
            }
        }
        say "keyword $keyword not found";
    }