Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Traversing a set of hashes

Reply
Thread Tools

Traversing a set of hashes

 
 
jkstill
Guest
Posts: n/a
 
      11-20-2007
I am trying to do something with hashes that I have not before.

While I am sure it can be done, I can't think of a good way to do it.

Given the following hash:

my %h = (
'first' => {
f0 => 'f_zero',
f1 => 'f_one',
},
'second' => {
s0 => 's_zero',
s1 => 's_one',
}
);

.... print all possible combinations

Easy enough using 2 nested loops.
Four combinations would be printed.

Extend the hash to this:

my %h = (
'first' => {
f0 => 'f_zero',
f1 => 'f_one',
},
'second' => {
s0 => 's_zero',
s1 => 's_one',
}
'third' => {
t0 => 't_zero',
t1 => 't_one',
}
);

This now requires 3 nested loops to get all possible combinations.

The problem is that the number of hashes nested in the %h hash
will not be known until runtime, so hardcoded loops won't work too
well.

Any tips on how to go about this?

TIA

Jared

 
Reply With Quote
 
 
 
 
jl_post@hotmail.com
Guest
Posts: n/a
 
      11-21-2007
On Nov 20, 4:58 pm, jkstill <(E-Mail Removed)> wrote:
>
> Given the following hash:
>
> my %h = (
> 'first' => {
> f0 => 'f_zero',
> f1 => 'f_one',
> },
> 'second' => {
> s0 => 's_zero',
> s1 => 's_one',
> }
> );
>
> ... print all possible combinations
>
> Easy enough using 2 nested loops.
> Four combinations would be printed.
>
> Extend the hash to this:
>
> my %h = (
> 'first' => {
> f0 => 'f_zero',
> f1 => 'f_one',
> },
> 'second' => {
> s0 => 's_zero',
> s1 => 's_one',
> },
> 'third' => {
> t0 => 't_zero',
> t1 => 't_one',
> }
> );
>
> This now requires 3 nested loops to get all possible combinations.



I don't agree. Both definitions of %h show it to be a hash of
hashes, meaning it will only need an inner loop nested inside an outer
loop (what I'd call one nested loop).

The following code (using only two while() loops) will print out
the contents of %h no matter how many hash entries it contains:

while (my ($key, $value) = each(%h))
{
print "In '$key':\n";
while (my ($key, $value) = each(%$value))
{
print " $key => $value\n";
}
}

Running this code on the hash with three elements will give this
output:

In 'first':
f0 => f_zero
f1 => f_one
In 'second':
s1 => s_one
s0 => s_zero
In 'third':
t0 => t_zero
t1 => t_one

This is what you want, isn't it?

Incidentally, you can easily print out a hash, no matter how many
elements it has or how deep it is, by using the standard Data:umper
module. Just use the following in your code:

use Data:umper;
print Dumper \%h;

And voila'! You'll see the entire contents of the %h hash.

I hope this helps, Jared.

-- Jean-Luc
 
Reply With Quote
 
 
 
 
Ted Zlatanov
Guest
Posts: n/a
 
      11-21-2007
On Tue, 20 Nov 2007 15:58:39 -0800 (PST) jkstill <(E-Mail Removed)> wrote:

j> I am trying to do something with hashes that I have not before.
j> While I am sure it can be done, I can't think of a good way to do it.
....
j> The problem is that the number of hashes nested in the %h hash
j> will not be known until runtime, so hardcoded loops won't work too
j> well.

Try the CPAN Data::Match module. It's very good for this kind of data
extraction, though it might be too advanced if you are not comfortable
with Perl data structures yet.

Ted
 
Reply With Quote
 
Ben Morrow
Guest
Posts: n/a
 
      11-21-2007

Quoth jkstill <(E-Mail Removed)>:
> I am trying to do something with hashes that I have not before.
>
> While I am sure it can be done, I can't think of a good way to do it.
>
> Given the following hash:
>
> my %h = (
> 'first' => {
> f0 => 'f_zero',
> f1 => 'f_one',
> },
> 'second' => {
> s0 => 's_zero',
> s1 => 's_one',
> }
> );
>
> ... print all possible combinations


It's not clear what you mean here by 'combinations'. I'm assuming you
mean 'combinations of values', so the result would be [[f_zero, s_zero],
[f_zero, s_one], [f_one, s_zero], [f_one, s_one]].

> Easy enough using 2 nested loops.
> Four combinations would be printed.


So you do mean what I said... the first thing to realize is that your
data structure should be arrays, not hashes:

[ ['f_zero', 'f_one'], ['s_zero', 's_one'] ]

since you don't make use of the keys.

> Extend the hash to this:
>

<snip: 3 inner hashes>
>
> This now requires 3 nested loops to get all possible combinations.
>
> The problem is that the number of hashes nested in the %h hash
> will not be known until runtime, so hardcoded loops won't work too
> well.
>
> Any tips on how to go about this?


The first thing that come to (my) mind is recursion, but of course you
can do it with loops as well. You only need three nested loops to handle
any number of cases.

#!/usr/bin/perl -l

use warnings;
use strict;

my %h = (
first => {
f1 => 'f1',
f2 => 'f2',
},
second => {
s1 => 's1',
s2 => 's2',
},
third => {
t1 => 't1',
t2 => 't2',
},
fourth => {
41 => '41',
42 => '42',
43 => '43',
},
);

$, = ',';

print "recurse:";

sub find_combs;

print @$_ for find_combs values %h;

sub find_combs {
my $entry = shift;

my @values = sort values %$entry;
@_ or return map [$_], @values;

my @recurse = find_combs @_;
my @rv;

for my $v (@values) {
push @rv, map [$v, @$_], @recurse;
}

return @rv;
}

print "reduce:";

use List::Util qw/reduce/;

my @lol = map [sort values %$_], sort values %h;
my $first = shift @lol;

our ($a, $b); # silence warnings

print @$_ for @{
reduce { # one...
[
map { # two...
my $tmp = $_;
map [$tmp, @$_], @$a; # three loops
} @$b
]
} [map [$_], @$first], @lol # (this map doesn't count )
};

__END__

Ben

 
Reply With Quote
 
jkstill
Guest
Posts: n/a
 
      11-21-2007
On Nov 20, 5:14 pm, "(E-Mail Removed)" <(E-Mail Removed)> wrote:
>
> This is what you want, isn't it?


Well, no, not actually.

All possible combinations of the three.
That would be 8 combinations of values each from each of the 3 nested
hashes.

I should have explained more clearly.

Thanks for the reply.
 
Reply With Quote
 
Ben Morrow
Guest
Posts: n/a
 
      11-21-2007

Quoth Ben Morrow <(E-Mail Removed)>:
>
> use List::Util qw/reduce/;
>
> my @lol = map [sort values %$_], sort values %h;
> my $first = shift @lol;
>
> our ($a, $b); # silence warnings
>
> print @$_ for @{
> reduce { # one...
> [
> map { # two...
> my $tmp = $_;
> map [$tmp, @$_], @$a; # three loops
> } @$b
> ]
> } [map [$_], @$first], @lol # (this map doesn't count )
> };


Duh, I don't need to special-case the first item, just start with the
appropriate identity. Then it becomes a one-liner (always nice):

print @$_ for @{
reduce {
[
map {
my $tmp = $_;
map [$tmp, @$_], @$a;
} @$b
]
} [ [] ], map [sort values %$_], sort values %h
};

Ben

 
Reply With Quote
 
jkstill
Guest
Posts: n/a
 
      11-21-2007
On Nov 20, 5:32 pm, Ben Morrow <(E-Mail Removed)> wrote:
>>

> So you do mean what I said... the first thing to realize is that your
> data structure should be arrays, not hashes:
>
> [ ['f_zero', 'f_one'], ['s_zero', 's_one'] ]
>
> since you don't make use of the keys.


This is just a prototype used to understand how to build something
else.
I need the hashes.

>
> The first thing that come to (my) mind is recursion, but of course you
> can do it with loops as well. You only need three nested loops to handle
> any number of cases.
>
>

Excellent! This does exactly what I need.

I'll play with it so I can understand how it works.

Jared

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
On Hashes - How the hashes printing works? Neela megha shyam Chivukula Ruby 4 05-28-2009 10:56 AM
How to make an array of hashes to a single array with all thevalues of these hashes ? kazaam Ruby 12 09-13-2007 01:30 PM
using hashes as keys in hashes Steven Arnold Ruby 3 11-23-2005 03:25 PM
Hash of hashes, of hashes, of arrays of hashes Tim O'Donovan Perl Misc 5 10-28-2005 05:59 AM
Hashes of Hashes via subs Ben Holness Perl 8 10-08-2003 06:57 AM



Advertisments