Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Multiple Unordered Hash Keys

by neosamuri (Friar)
on Mar 26, 2008 at 21:35 UTC ( [id://676555]=perlmeditation: print w/replies, xml ) Need Help??

While working on a recent project, I ran across a case where having a hash with multiple unordered keys would have been helpful. By multiple unordered keys I mean:

$hash{'keyA','keyB'} = "Some Value"; print $hash{'keyB', 'keyA'}; # prints "Some Value";

After looking around on CPAN, I could not find a module that allowed this, and ended up writing my own. The code is here:

package Hash::MultiKey::Unordered; use strict; use warnings; sub TIEHASH { my $class = shift; bless {}, $class; } sub FETCH { my $hash = shift; my $key = shift; return $hash->{ _fix($key)}; } sub STORE { my $hash = shift; my $key = shift; my $value = shift; $hash->{_fix($key)} = $value; } sub DELETE { my $hash = shift; my $key = shift; return delete $hash->{_fix($key)}; } sub EXISTS { my $hash = shift; my $key = shift; return exists $hash->{_fix($key)}; } sub FIRSTKEY { my $hash = shift; keys %$hash; return each %$hash; } sub NEXTKEY { my $hash = shift; return each %$hash; } sub SCALAR { my $hash = shift; return scalar %$hash; } sub _fix { my $key = shift; my(@keys) = split /$;/, $key; @keys = sort @keys; $key = join $;, @keys; return $key; } 1;

My questions are:

  • Is it worth more attention?
  • Should it be contributed it to CPAN?
  • What would be a better name for the module?

Replies are listed 'Best First'.
Re: Multiple Unordered Hash Keys
by Arunbear (Prior) on Mar 26, 2008 at 23:43 UTC
    This is a neat idea (I even learned what $; does!). Hash::MultiKey is safer in its handling of multi-keys, but doesn't support unordered keys. Why don't you base your implementation on that of Hash::MultiKey but adjust it to support unordered keys?
Re: Multiple Unordered Hash Keys
by ysth (Canon) on Mar 27, 2008 at 02:55 UTC
Re: Multiple Unordered Hash Keys
by samtregar (Abbot) on Mar 26, 2008 at 22:19 UTC
    Plausibly useful, sure put it on CPAN. You could cut a lot of that code by basing your code on Tie::StdHash.

    -sam

Re: Multiple Unordered Hash Keys
by mr_mischief (Monsignor) on Mar 26, 2008 at 22:20 UTC
    It's certainly interesting. What, exactly, though, does all that tie'ing buy you that's so much better than the following?

    $hash{ 'keyA' }{ 'keyB' } = "Some Value"; print $hash{ 'keyA' }{ 'keyB' };

    Yes, having the keys unordered could theoretically be nice, but in what situations do you find it's an issue?

    If it's really necessary, you could in the exact case you need it do this:

    @foo = ( 'keyB', 'keyA' ); $hash{ join '', sort @foo } = "Some Value\n"; print $hash{ join '', sort @foo };

      In the problem I had, I had 2 references that I needed to know if I had already tested them, and what the result is. The first thing that came to mind was using the hash. The problem is that you don't know if refA or refB is the first key into the hash, so you have to test both.

      if( $tests{ $refA, $refB } or $tests{$refB, $refA} ) { # some stuff } # as opposed to if( $tests{ $refA, $refB} ) { # order not important # some stuff }

      The reason for using the tied interface instead of verbosely writing out the sort join, is so that you don't have to see that extra code, which doesn't add to the understanding of the code, but instead clouds it.

        sub mk { join '', sort @_ } $hash{ mk 'a', 'b' } = 'Some Value'; print $hash{ mk qw{ b a } };

        It's still a little bit of extra typing, I'll admit. It doesn't involve modifying how the hash code works, though. I don't think having a few extra characters obfuscates the hash usage at all.

        You might also notice that by joining with an empty string, you're able to use arrays as well as lists. That's one of the benefits of Hash::MultiKey over standard Perl multi-keyed hashes, but without the tie.

        Another advantage is that in many cases you can do the sort and join once, saving the result into a simple scalar for later use. It may be frowned upon as a premature optimization, but it could help the clarity of the code over a tied hash.

        In your example, I'm not quite certain why you'd be storing the results of two tests as one entry in the hash in the first place. Are you specifically testing pairs of mutually dependent items?

        if ( $tests{ $refA } && $tests{ $refB } ) { # This checks two hash entries very cleanly, but falls down # if the results are dependent on whether A and B are tested together +. # some stuff }

        With something like Hash::MultiKey, I'm not sure from the top of my head when I'd use the fact that each() and keys() return an arrayref of strings instead of the concatenated string, but surely someone's found a use for that feature because it's all over the examples. If I thought of a solid reason I'd want that, then using a module which does that would probably be worthwhile.

        I'm not trying to discourage you from publishing your module; I'm just giving you the feedback you requested. I, personally, probably won't use your module. If you find your module useful enough to put it on CPAN, other people will probably find it useful enough to download from CPAN.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (2)
As of 2024-04-26 00:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found