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

Starting, I'm not really sure if this is less of a question than a meditation, though I'll put it here anyways.

Recently, and once in the past, I have run into algorithems where it would be sweet to have a array-ref as a hash-key. I realize this isn't *directly* possible (without having the stringified version of the ref as the key rather than the ref its self), and I am aware of modules on CPAN as well as similar perlmonk writeups on this issue, though I am seeking the guidance from others who have stumbled across similar situations that may have found a slick way to work with this limitation while not having to install or use any modules to do so.

A major disclaimer being: I am a HUGE fan of programatic data structures. By this I mean I have a tendancy to create static complex data structures that will allow for conditional switching, and cool one-liners to utilize easily modifiable structures rather than having to go back for raw logic changes later; just change the structure.

Real Question:
Now that you've read my little book, here is the situation I ran into recently. Basically, lets say I have one hash $hash_one. Now, I want to test $hash_one for key a, b, c, etc. If all three are defined, I want to copy the hash into two new hashes, each with new, yet different sets of defaulted keys. Along the same lines, if different combinations of said keys are defined, I would want to copy the hash n, each with different default values, etc. Mind again, I didn't want to create any new objects, import any external modules, etc. for this solution.

Therefore, if I we're to have the following data structure:
my $struct = { [ qw( a b c ) ] => [ { 'a' => 1, 'b' => 2, 'c' => 3, }, { 'a' => 0, 'b' => 1, 'c' => 2, } ], };
I could simply test the hash, $hash_one, for keys in [qw(a b c)], all are true, I could then copy $hash_one for each iteration within the valued array-reference, I could then clobber the values in the newly copied array with that in each of the hash-refs.


Phew! I realize this is pretty wierd, and a very unique situation, and one that is not really all that possible to solve in this manner. However, my 'question' is:


Has anyone else out there ever ran into something like this (or understand what the heck I'm even saying). If so, how did you solve it??

I have found a pretty nifty answer to this problem since, yet it's still one of the only last limitations to Perl that I've had to bang my head against the wall against... and just say to my self "Perl, you can do everything else 10 different ways, except for the one thing I want right now".

Maybe I'm just nuts and need to de-complex my code... hm.

---hA||ta----
print map{$_.' '}grep{/\w+/}@{[reverse(qw{Perl Code})]} or die while ( 'trying' );

Replies are listed 'Best First'.
Re: Array refs as hash keys
by Celada (Monk) on Dec 16, 2005 at 05:01 UTC

    I should say that I don't believe I've fully understood what you're looking for.

    In answer to the first part of your question, if you need to use any kind of reference as a hash key, what's wrong with using the stringified version of it as a hash key? It's unique (even under threads and fork) so it should do the trick. Yet you should think about what this means: it is the reference itself that it the key in this case, not the contents (whatever you get when you deference it). Is this what you mean? Maybe. I can think of times when this is useful. The only caveat is that the stringified version of the reference won't increase the reference count of the object itself, so you will have to be careful that the object isn't destroyed when you still need it. Embedding the reference inside the value of the hash element for which it is the key might be a good trick to force that.

    In the second part of your question though you seem to want something different: you seem to want to index based on the value of the object pointed to. This will not work of course: [ qw( a b c ) ] != [ qw (a b c ) ] (they are different objects). Do you want to use a serialized (stringified) representation of the contents of the reference? That's not very doable in general (think of self referential data structures or structures that contain code references). So I guess it depends on what you are really trying to do.

    A major disclaimer being: I am a HUGE fan of programatic data structures. By this I mean I have a tendancy to create static complex data structures that will allow for conditional switching, and cool one-liners to utilize easily modifiable structures rather than having to go back for raw logic changes later; just change the structure.

    I don't consider that "disclaimer material". Behaviour driven by data ans the real "code" only acts in support of that. It's very maintainable and often self documenting. A very good practice, in my opinion, as long as you pay attention to security issues.

      Thanks for the reply, and such a detailed one at that.

      I guess my real question was somewhat lost in my lenghty description of my recent situation. Really, it was more of a design philosiphy question rather than a Perl question.

      To be clearer: [ qw( a b c ) ] (could be) == [ qw( a b c ) ] when you are referencing the reference to the anonymous array back as the reference to the key. Again, I know this isn't possible... and I also realize that the stringified value could be unique (though not guaranteed since it is to be the memory reference address which could be re-used by another object/struct/etc), still not exactly what I was looking for.

      Really, I know I can't do this as I really want to. It was a methodology I used when I designed apps in (dare I say it) Java (and a long time ago, when I was a little dumber). I was really hoping to see if anyone else has ran into such a situation, and if so, how did they get around it.

      Thanks again for your reply, though; sometimes it's harder to explain a programatic situation in a textfield that I sometimes give myself credit for.

      ---hA||ta----
      print map{$_.' '}grep{/\w+/}@{[reverse(qw{Perl Code})]} or die while ( 'trying' );