Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

how to iterate over multiple hashes with same key value

by sunil9009 (Acolyte)
on Jul 02, 2013 at 06:03 UTC ( #1041956=perlquestion: print w/replies, xml ) Need Help??
sunil9009 has asked for the wisdom of the Perl Monks concerning the following question:

I have a text file named cust with 3 fields, time, customer name, location
$ cat cust 12:10 a america 12:11 b bombay 12:12 c calcutta 12:13 a australia 2:30 b bhutan 3:40 n neterland
Created a script to iterate over each hash $ cat
#!/usr/bin/perl open FILE1, "cust" or die; my %hash; my %location; while (my $line=<FILE1>) { chomp($line); (my $word1,my $word2, my $word3) = split /\s+/, $line; push (@{$hash{$word2}},$word1); push (@{$location{$word2}},$word3); } for $user (sort keys %hash) { print "$user: @{$hash{$user}} \n"; } for $loc (sort keys %location) { print "$loc: @{$location{$loc}} \n"; }
Getting the following output: $ ./
a: 12:10 12:13 b: 12:11 2:30 c: 12:12 n: 3:40 a: america australia b: bombay bhutan c: calcutta n: neterland
Instead I want the output something like the following. Can you guys please help.
a: 12:10 12:13 : america australia

Replies are listed 'Best First'.
Re: how to iterate over multiple hashes with same key value
by kcott (Canon) on Jul 02, 2013 at 06:58 UTC

    G'day sunil9009,

    I strongly suspect poorly named variables are one of your biggest problems here:

    • %hash — we already know it's a hash (by the % sigil), beyond that the name is meaningless: it neither reflects the keys (which are customer names) nor the values (which are times).
    • $word1, $word2, $word3 — all meaningless and tells us nothing about the data they hold.
    • $user — started off as customer names, now they're users.
    • $loc — fairly common as an abbreviation for "location" except it holds customer names not locations.

    Not surprisingly, when you got to printing your results, you had no idea what data was held where!

    You probably want something closer to this:

    $ perl -Mstrict -Mwarnings -le ' my @file_data = ( "12:10 a america", "12:11 b bombay", "12:12 c calcutta", "12:13 a australia", "2:30 b bhutan", "3:40 n neterland" ); my %name_data; for (@file_data) { my ($time, $name, $loc) = split; push @{$name_data{$name}{time}} => $time; push @{$name_data{$name}{loc}} => $loc; } for my $name (sort keys %name_data) { print "$name: @{$name_data{$name}{time}} : @{$name_data{$name} +{loc}}"; } ' a: 12:10 12:13 : america australia b: 12:11 2:30 : bombay bhutan c: 12:12 : calcutta n: 3:40 : neterland

    Other issues:

    • You haven't used strict.
    • You haven't used warnings.
    • You've used the 2-argument form of open.
    • You call die without a message. If you don't want to hand-craft a message, use autodie instead.

    -- Ken

      Thank you guys for the solutions. Its amazing to get such knowledge from gurus of perl.
Re: how to iterate over multiple hashes with same key value
by hdb (Prior) on Jul 02, 2013 at 06:12 UTC

    I see two options:

    1. As per your script, you populate %hash and %population%location in such a way that they have the same keys. So you could just move the print statement from your "locations" loop into the "users" loop (it would also make sense to rename %hash to %users).
    2. Alternatively, you could add another dimension to your %hash such that you store both times and locations in the hash. For example:
      push (@{$hash{$word2}{'times'}},$word1); push (@{$hash{$word2}{'locations'}},$word3);
      This way you would keep the data closer together.

    EDIT: Changed %population to %location (thanks kcott)

Re: how to iterate over multiple hashes with same key value
by Utilitarian (Vicar) on Jul 02, 2013 at 06:21 UTC
    When examining your data you should probably examine what you want to take from it before deciding how to store it, in this case 2 arrays keyed on the first column best represent your intended use of the data, there's no need to create separate data structures, in fact having a single data structure makes passing it to subsequent functions easier.

    So here's a solution using a single data structure with each customer referencing 2 arrays, one for time and the other for location.

    ~/$ cat #!/usr/bin/perl use strict; use warnings; open(my $customers, $ARGV[0])|| die "Couldn't open $ARGV[0] $!\n"; my %cust; while(<$customers>){ chomp; my @rec=split(/\s+/, $_); push @{$cust{$rec[1]}->{time}},$rec[0]; push @{$cust{$rec[1]}->{location}},$rec[2]; } for my $cust (sort keys %cust){ print "$cust: ",join(" ",@{$cust{$cust}->{time}})," : ",join(" ",@ +{$cust{$cust}->{location}}),"\n"; } ~/$ perl tmp.dat a: 12:10 12:13 : america australia b: 12:11 2:30 : bombay bhutan c: 12:12 : calcutta n: 3:40 : neterland
    Moved from duplicate thread
    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: how to iterate over multiple hashes with same key value
by Laurent_R (Abbot) on Jul 02, 2013 at 06:28 UTC

    Your choice of data structure is poor. Whenever you are using to hashes with the same keys, you should think about using a hash of hashes, or hash of arrays, or whatever suits uour needs the best.

    However, since you have the same keys you could do something like this:

    for $user (sort keys %hash) { print "$user: @{$hash{$user}} \t"; print "$loc: @{$location{$loc}} \n"; }

    EDIT: my copy and paste was too hasty (the train from which I posted it was arriving at my destination). It should be something like this:

    for $user (sort keys %hash) { print "$user: @{$hash{$user}} \t"; print "$user: @{$location{$user}} \n"; }

      I do not think the latter will work as $loc will be undefined...

        Yes, right, my answer was too hasty, I updated my post now.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1041956]
Approved by hdb
[thezip]: G'day all. Apparently Strawberry Perl has issues with deploying Spreadsheet::XLSX for Perl 5.24.1. I need this module to maintain compatability with an existing script. I'm new to Strawberry -- is there a safe way to manually deploy this?
[MidLifeXis]: Where is it hanging up?
[MidLifeXis]: ISTR having a couple of issue based on undeclared dependencies around the time I was looking at that module on my last project, but cannot say if that was the module that I had the dependency issues with.
[MidLifeXis]: (5.22 at that time)
[MidLifeXis]: Yeah, I know, really helpful :-)
[Corion]: If all else fails, Spreadsheet::XLSX should be "installable" by manually copying the files, provided that the prerequisites are met
[thezip]: It fails in the "formatted 2-digit numeric" tests
[thezip]: Okay Corion, that's what I wanted to hear. Thanks!
[Corion]: Oh, a test failure... Just force-install it then? --force and potentially --notest to skip the tests alltogether ?

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (14)
As of 2017-03-23 17:12 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (290 votes). Check out past polls.