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

Hi Monks, Is there any way of getting a list of keys from a tied Ix::Hash that contains several repeated entries? Example:
#!/usr/local/bin/perl use strict; use Tie::IxHash; my %foo; my $t = tie %foo, 'Tie::IxHash'; #integer part of... %foo = qw ( one 1.2 one 1.6 one 1.9 two 2 three 3 ); my @keys = $t->Keys; print "@keys\n";
This will print One, two, three instead of one, one one, two three. Any ideas? It's a common situation. It would be a nice addition to Q&A. Thanks, quesada

Replies are listed 'Best First'.
Re: Ix::Hash with repeated keys
by $code or die (Deacon) on Sep 26, 2001 at 07:21 UTC
    You might want to look at Tie::DxHash. I think this does what you want. Tie::IxHash only allows one value per key - Tie::DxHash allows duplicate keys although the documentation is not so good.

    Untested code:
    use strict; use Tie::DxHash; my %foo; tie %foo, 'Tie::DxHash'; %foo = qw ( one 1.2 one 1.6 one 1.9 two 2 three 3 ); my @keys = keys %foo; print "@keys\n"; # if @keys only has each key once, try this: foreach my $key (@keys) { print "$key, " foreach ($foo{$key}) }
    Try it and see what happens - if it doesn't work, you might want to take another look at what you're doing and see if you can do whatever you're trying to do. Perhaps maintain a seperate count every time you add\delete a value.

    Update: You don't really need a module to do this. Have a look at perldsc. You can create a type of hash that allows multiple values - a hash of arrays - i.e. each hash key points to an anonymous array. It would look like this:
    %hash = ( one => [1.2, 1.6, 1.9], two => [2], three => [3]);
    Look into perldsc anyway because I think this is best method.

    Simon Flack ($code or die)
    $,=reverse'"ro_';s,$,\$,;s,$,lc ref sub{},e;$,
    =~y'_"' ';eval"die";print $_,lc substr$@,0,3;
Re: Ix::Hash with repeated keys
by dvergin (Monsignor) on Sep 26, 2001 at 07:01 UTC
    Hashes don't work this way. Each key must be and will be unique. No way around it. So what you are doing is setting $foo{one} to 1.2 ...and then to 1.6 ...and finally to 1.9

    Tie::IxHash only preserves the order that the hash elements were created. It does not over-ride the one-value-per-key characteristic of hashes.

    You cannot do what you are trying to do with hashes. Perhaps if you told us more about the problem you are trying to solve, we could suggest some ways to address it.

    And when you have a some time, take a look at the section of perlvar that deals with hashes. They are a rich and wonderful tool when used as intended.

    HTH, David