Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

add values with hash

by steph_bow (Pilgrim)
on Mar 11, 2008 at 13:19 UTC ( [id://673489]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks,

My program uses a hash table to capture data, but for the same key there are several values in the input files. So I had to make two hash tables because there are two different values for the same key. It works. But I do not know how to generalise with three or more without having to use my %hash_3, my %hash_4, ... Could you check ? Thanks

Here is the code

#!/usr/bin/perl use strict; my $inFile = q{animals.txt}; open my $INFILE, q{<}, $inFile or die; my %hash; my %hash_2; while (<$INFILE>) { $_ =~ s/\s+$//; if (/^forest(\s+)(\w+)/){ my $country = $2; while (<$INFILE>){ chomp($_); if (/^-fox.*(\d\d\d\d)/){ chomp; my $fox_hour = $1; if (defined $hash{$country}){ $hash_2{$country}=$fox_hour; } else{ $hash{$country}=$fox_hour; } } last if (/monkey/); } } } close $INFILE; my $c_outfile = q{countries_results.csv}; open my $c_OUTFILE, q{>}, $c_outfile or die; my $c_inFile = q{countries_list.csv}; open my $c_INFILE, q{<}, $c_inFile or die; my $country; while (my $line = <$c_INFILE>){ my @Elements = split(";",$line); $country = $Elements[0]; $country =~ s/\s+$//; print $c_OUTFILE "$country;$hash{$country};$hash_2{$country}\n"; } close $c_INFILE; close $c_OUTFILE;

Here are the two input files

Here is the input file "animals.txt"

forest France -wolf -toad -fox 1350 monkey land -dog -cat -slug forest France -deer -swan -fox 1426 monkey forest USA -deer -swan -fox 1560 monkey

Here is "countries_list"

Italy USA France

And here are the output results

Italy;; USA;1560; France;1350;1426

Replies are listed 'Best First'.
Re: add values with hash
by igelkott (Priest) on Mar 11, 2008 at 13:34 UTC
    When you have several values for each key, you might want to use a Hash of Arrays.
Re: add values with hash
by Narveson (Chaplain) on Mar 11, 2008 at 13:44 UTC

    Instead of

    if (defined $hash{$country}){ $hash_2{$country}=$fox_hour; } else{ $hash{$country}=$fox_hour; }
    say
    push @{ $hash{$country} }, $fox_hour;

Re: add values with hash
by wfsp (Abbot) on Mar 11, 2008 at 13:47 UTC
    As igelkott says a HoA is the way to go. It looks as though monkey is the record separator. Setting Perl's record separator might help.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; $Data::Dumper::Indent = 1; $/ = q{monkey}; my %hash; while (<DATA>){ my ($country, $fox_hour) = /forest\s+(\w+).*-fox\s+(\d{4})/s; next unless $country; push @{$hash{$country}}, $fox_hour; } print Dumper \%hash; __DATA__ forest France -wolf -toad -fox 1350 monkey land -dog -cat -slug forest France -deer -swan -fox 1426 monkey forest USA -deer -swan -fox 1560 monkey
    outputs
    $VAR1 = { 'France' => [ '1350', '1426' ], 'USA' => [ '1560' ] };
    update: added link
Re: add values with hash
by DACONTI (Scribe) on Mar 11, 2008 at 15:00 UTC
    Hi steph,
    in order to solve your problem I recommend you first to look at hashes of hashes and autovivification in some perl book.
    (For ex. Programming Perl)
    Personally, for problems of your kind, I like to use hash references like in the example below:
    use strict; my $hash={}; $hash->{countries}->{USA}->{animals}->{fox}=1560; $hash->{countries}->{Italy}={}; while ( my ($country, $country_ref) = each %{$hash->{countries}} ) { print "$country\n"; print $country_ref->{animals}->{fox}."\n" if exists $country_ref->{animals}->{fox}; };
    By building hashes in this way
    $hash->{countries}->{USA}->{animals}->{fox}=1560;
    I can easily write very complex hash structures
    In addition if you look carefully at the example above, you will remark that there is this kind of convention:
    metadata->data->'detail metadata'->'detail data'
    . If you do like that you have a single structure to which you can add at any time new dimensions without loosing degrees of freedom.
    It shouldnt be too difficult to match this strategy to your actual problem.
    Best Regs,
    Davide.
Re: add values with hash
by dwm042 (Priest) on Mar 11, 2008 at 15:55 UTC
    I am sure there are many excellent answers to this question. But I decided to write a piece of code that demonstrates various ways to add multiple values to a single hash key:

    #!/usr/bin/perl use warnings; use strict; # # There are a lot of ways to associate a single hash key # With multiple values. We will demonstrate some of # these in this code: # my %hash = (); # # Using a hash element to store an (anonymous) array. # $hash{array_key} = [ 1,2,3,4,5 ]; # # using a hash element as a stack. # push @{$hash{array_key}}, 6; print "Array values are: ", join(' ',@{$hash{array_key}}), "\n"; # # Using a hash element to store a reference to an array # my @array = ( 2,3,4,5,6 ); $hash{array_ref} = \@array; # # Using a hash element to store an anonymous hash. #(Hash of hashes) # $hash{anon_hash} = { first_name => "Fred" , last_name => "Flintstone" +}; print_hash(\%{$hash{anon_hash}}); # # Using a hash element to store a reference to a hash. #(Hash of hashes) # my %neighbor = ( first_name => "Barney", last_name => "Rubble", ); $hash{hash_ref} = \%neighbor; print_hash(\%{$hash{hash_ref}}); # # Using a hash element to store an anonymous copy of a hash. #(hash of hashes) # my %wife = ( first_name => "Wilma", last_name => "Flintstone", ); $hash{hash_copy} = { %wife }; $hash{hash_copy}{first_name} = "Betty"; $hash{hash_copy}{last_name} = "Rubble"; print_hash(\%wife); print_hash(\%{$hash{hash_copy}}); sub print_hash { my $hashref = shift; print "Hash values: "; for ( sort keys %{$hashref} ) { print $$hashref{$_}, " "; } print "\n"; }
    And the output is:

    C:\Code>perl hash_examples.pl Array values are: 1 2 3 4 5 6 Hash values: Fred Flintstone Hash values: Barney Rubble Hash values: Wilma Flintstone Hash values: Betty Rubble

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2024-04-19 20:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found