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

Hello! I am new to perl. And now I need monks' help with a problem related to hash.

I am trying to merge two hashes. I have fields of time, conference, type, comment. I have no problem with time as hash key.

while (<FILE>)
{
my %hash = ();
$hash{$time}{'conference'} = $value1;
$hash{$ime}{'type'} = $value2;
$hash{$time}{'comment'} = $value3;
}

for my $time (sort keys %hash)
{
print .... #element
}

But how do I do the same thing (add element and access later) if I use time and conference as multi value key in the hash. I could add time and conference to the key using push, but how to refer to it to add $type, $comment and later to print all four fields?

Thanks for help!

Replies are listed 'Best First'.
Re: question about multi value hash key
by kyle (Abbot) on Mar 31, 2009 at 22:06 UTC

    I'm not quite clear on what you're trying to do. It sounds as if maybe you have more than one conference at a time, and you want to store them all under the same hash key.

    I suggest that you work with hash references that contain all of the conference information in one hash.

    { time => $time, conference => $value1, type => $value2, comment => $value3, }

    You can take one of those and stick it in a hash of arrays (of hashes) or just have an array of them.

    push @AoH, { time => $t, conference => $v1, ... };

    Then you can sort the array by time when you want to output them.

    my @sorted_AoH = sort { $_->{time} <=> $_->{time} } @AoH; foreach my $conf ( @sorted_AoH ) { my $time = $conf->{time}; print ... # element }

    If you need random access to these records by time, then you can put them in a hash as you have them but add a layer of array to it.

    push @{ $hash{$time} }, { time => $time, type => $v2, ... };

    Then you need an extra loop when dealing with them.

    for my $time ( sort keys %hash ) { for my $conf ( @{ $hash{ $time } } ) { print ... # $conf element } }

    Again, I'm not clear from your description what you're trying to do, but maybe this gives you some ideas.

Re: question about multi value hash key
by moritz (Cardinal) on Mar 31, 2009 at 21:25 UTC
    Your hash keys are always a singles strings. You can of course chose something like time and conference, separated by a special character, as a combined key - but what would you gain?

    In general a Hash is a String-to-Thing mapping, not a relational database.

    (oh, and please use <code>...</code> tags around example code that you post here, that'll make it easier to read).

Re: question about multi value hash key
by codeacrobat (Chaplain) on Mar 31, 2009 at 22:24 UTC
    You should declare %hash outside the while loop otherwise its not visible, when you print the results in the for loop. Time and conference should also be stored as value in hash record although the information is already available in the timeconference multivalued key. This makes later access easy. Try something like this.
    use strict; use warnings; my %hash = (); my ($time, $conference, $type,$comment); while(<FILE>) { # adapt parsing values to your need here if (/conference=(.*)/){ $time = $1; } if (/conference=(.*)/){ $conference = $1; } if (/type=(.*)/){ $type = $1; } if (/comment=(.*)/){ $comment = $1; } if (/lastline of record/){ $hash{$time,$conference}{time} = $time; $hash{$time,$conference}{conference} = $conference; # info is a +lready in the key, for easy parsing in the for loop, store conference + twice. $hash{$time,$conference}{type} = $type; $hash{$time,$conference}{comment} = $comment; } } for my $timeconference (sort keys %hash) { printf "time %s, conference %s, type %s, comment %s\n", @{hash}{qw(time conference type comment)}; }

    print+qq(\L@{[ref\&@]}@{['@'x7^'!#2/"!4']});
Re: question about multi value hash key
by locked_user sundialsvc4 (Abbot) on Mar 31, 2009 at 22:51 UTC

    It is certainly possible to create, say, a hash which contains an arrayref which in turn contains a list of references to records. It's also certainly possible to create more than one such structure which refers-to the same record.

    In other words... “oh yes, you can do this in Perl, but...”

    But before I proceeded too far in that direction, I think I'd be asking myself this hard question:   “is what I really want to use here just ‘an SQL database?’ ”

    When your well-laid plans begin to “smell funny,” follow your gut.

Re: question about multi value hash key
by Ish (Acolyte) on Mar 31, 2009 at 22:14 UTC
    Hi joybee. From your description I'm not quite sure what you are trying to achieve. Could you please elaborate?
Re: question about multi value hash key
by joybee (Initiate) on Apr 01, 2009 at 03:23 UTC
    Thanks everyone for the help. This is my second post and I am not familiar with the format. Please don't mind my clumsiness.

    The problem that I have is to merge two files which have the same fields (time, conference, type, comment) and to sort them out. The combination of (time, conference)is unique. When I tried it, I had the problem of how to address multi value key in hash. I had a sub to read files and write contents to two hashes and return the hash reference. But that was for single value key. I don't know how to do the same thing with muti-value key and how to use key reference to access multiple values in the hash. Hope I made the problem a little bit cleare.

      Perhaps a HoHoH would do it.
      #!/usr/bin/perl use warnings; use strict; my %conf_table = ( 1 => { conference1 => { type => q{type1}, comment => q{comment1}, }, conference2 => { type => q{type2}, comment => q{comment2}, }, }, 2 => { conference3 => { type => q{type1}, comment => q{comment3}, }, conference4 => { type => q{type2}, comment => q{comment4}, }, }, ); for my $time (keys %conf_table){ print qq{time: $time\n}; for my $cnf (keys %{$conf_table{$time}}){ print qq{\tconference: $cnf\n}; print qq{\t\ttype: $conf_table{$time}{$cnf}{type}\n}; print qq{\t\tcomment: $conf_table{$time}{$cnf}{comment}\n}; } }
      time: 1 conference: conference1 type: type1 comment: comment1 conference: conference2 type: type2 comment: comment2 time: 2 conference: conference4 type: type2 comment: comment4 conference: conference3 type: type1 comment: comment3
Re: question about multi value hash key
by ambrus (Abbot) on Apr 01, 2009 at 10:43 UTC

    Could I ask why you want to use the conference time as the first entry? Do you often want to search the hash for conferences at an exact time? (The hash won't help you searching conferences in eg. an interval between two given times, which is what you'd more often want.) If not, why don't you just use a single array of hashes, with each entry of the array storing one conference, and the time stored in another field just like how you store the conference name and type and comment.

    Update: oh, I see kyle has already suggested this.