Module for getting values from "flattened" hash or "recursed" hash...?

N

newsbot

I've search high and low in CPAN for a hash module to do the following,
as I describe here. With all the MANY hash modules out there, it's
hard to believe someone hasn't written at least something similar.

Given the following sample hash (reference(s)):

$h = {
'group1' => {
'green' => 'This is green',
'blue' => 'This is blue',
'gray' => {
'orange' => {
'pink' => 'This is gray-orange-pink (yuk!)',
'black' => 'This is gray-orange-black (eh...)'
},
'red' => 'This is gray-red',
'label' => 'This is a gray label',
'yellow' => 'This is gray-yellow'
},
'red' => 'This is red'
}
};

If I say "$rv = giveme( $h, 'green' );" where "giveme()" is some
hypothetical function, then I want $rv to receive "This is green". If
I say "($a,$b,$c) = giveme( $h, 'blue', 'pink', 'red' );" then I want
to receive "This is blue", "This is gray-orange-pink", and "This is
red" in return.

Notice that for "red", the {group1}->{red} takes precedence over the
{group1}->{gray}->{red}. The return context of scalar versus array
isn't as important -- I merely illustrate this way for sake of brevity
since "giveme()" is hypothetical -- the subject of my posting. Also,
the return of {group1}->{gray} is undefined, as is
{group1}->{gray}->{orange}, etc.

The Tie::proxy::Hash and Tie::Flatten modules are *close* to what I
want, but aren't exact. I could use either or both of them to perhaps
"massage" what I want, but I'd rather just write it myself if it
doesn't exist as above.

In the application which requires this functionality, I can virtually
guarantee that keys in the hash "tree" will be unique -- which lends
itself to a "flatten" namespace. But not always as in the case of
"red" above where {group1}->{red} takes precedence.

If anyone knows of a module to do this, I'd appreciate hearing about
it. I've searched Google and CPAN high and low...

-ceo
 
F

Fabian Pilkowski

Given the following sample hash (reference(s)):

$h = {
'group1' => {
'green' => 'This is green',
'blue' => 'This is blue',
'gray' => {
'orange' => {
'pink' => 'This is gray-orange-pink (yuk!)',
'black' => 'This is gray-orange-black (eh...)'
},
'red' => 'This is gray-red',
'label' => 'This is a gray label',
'yellow' => 'This is gray-yellow'
},
'red' => 'This is red'
}
};

If I say "$rv = giveme( $h, 'green' );" where "giveme()" is some
hypothetical function, then I want $rv to receive "This is green". If
I say "($a,$b,$c) = giveme( $h, 'blue', 'pink', 'red' );" then I want
to receive "This is blue", "This is gray-orange-pink", and "This is
red" in return.

Notice that for "red", the {group1}->{red} takes precedence over the
{group1}->{gray}->{red}.

But if your hash looks like

$h = {
'green' => { 'blue' => 'this is turquoise' }
'red' => { 'blue' => 'this is lilac' }
}

which 'blue' you're expecting, the greenish or the reddish one? ;-)
The return context of scalar versus array
isn't as important -- I merely illustrate this way for sake of brevity
since "giveme()" is hypothetical -- the subject of my posting. Also,
the return of {group1}->{gray} is undefined, as is
{group1}->{gray}->{orange}, etc.

What you really want is a simple postorder traversal for your hash to
search for the given colors. I haven't looked at CPAN yet if there's
such a modul for traversing hashes, but with a stack for pushing your
sub-hashes onto, your sub could look like:


sub giveme {
my @stack = shift;
my %color;

while ( @stack ) {
my( $key, $value ) = each %{$stack[0]}
or shift( @stack ), next;
ref( $value ) eq 'HASH'
and push( @stack, $value ), next;
$color{$key} ||= $value;
}

return @color{ @_ };
}


regards,
fabian
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top