Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Loop thru inner hash 1

Status
Not open for further replies.

CJason

Programmer
Joined
Oct 13, 2004
Messages
223
Location
US
Say I have a hash of a hash, defined as below:

%OUTER = (
OUT1 => {
IN1 => "I1",
IN2 => "I2",
},
OUT2 => {
IN1 => "I1",
IN2 => "I3",
},
);

How can I obtain all the OUTER hash values that have IN1 = "I1"? Of course, I know you can simply loop thru all the outer keys and compare the IN1's...but, that seems pretty inefficient and was hoping there was a better way.

Thanks in advance!
 
you have to loop through all the keys you are interested in, there is no way around that. How you loop through the hash might be of concern though.

- Kevin, perl coder unexceptional!
 
If you're only doing one search, then looping through will be the quickest and easiest method.

If you are doing repeated searches, then make an intermediate data structure that will enable you to do simple hash lookups. That's the only determining factor for which approach is more efficient.
 
good point Miller

- Kevin, perl coder unexceptional!
 
Miller and Kevin, thanks for your input!! Miller...YES, this search will be done repeatedly. Can you give me an example of what you mean by "make an intermediate data structure that will enable you to do simple hash lookups"? I'm not familiar with what you are referring to.

Thanks SO much!!!
 
Does someone know what Miller meant by: "make an intermediate data structure that will enable you to do simple hash lookups"?

Thanks!
 
Example: make a hash, %in1. Its keys are the values of all the 'IN1's, e.g I1, I2, I3 etc. Its values are arrays of keys into the main hash, e.g. OUT1 OUT2.

Loop through the main hash once, populating %in1 (you were going to loop through repeatedly anyway). So then $in1{'I1'} returns an array of all the OUTx keys with an inner value of in1 => 'I1'. If you have say, 10,000 OUTx keys, and only 22 of them have in1 => 'I1', then
Code:
for (@{$in1{'I1'}) {
   print "$_: in1 => $OUTER{$_}->{'in1'}\n";
}
should print them all without having to iterate over 10,000 hash keys.

It's kind of like an alternate index. You have to trade the cost of building it against how much time it saves. Which is why MillerH says
If you are doing repeated searches...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::PerlDesignPatterns)[/small]
 
For a simple one-off search, I'd just use a simple grep:
Code:
my @found = grep $OUTER{$_}{IN1} eq $to_find, keys %OUTER;
 
Currently your data structure is in the format of outer hash keys pointing to inner hash keys pointing to inner hash values. It sounds like now you want inner hash keys pointing at inner hash values pointing at outer hash keys. The only important thing to recognize is that you could end up with a one to many relationship to the outer hash keys. So to accommodate this you use an array for your final values:

Code:
my %OUTER = (
	OUT1 => {
		IN1 => "I1",
		IN2 => "I2",
	 },
	OUT2 => {
		IN1 => "I1",
		IN2 => "I3",
	},
);

my %searchOUTER;

while (my ($outerKey, $innerHash) = each %OUTER) {
	while (my ($innerKey, $innerVal) = each %$innerHash) {
		push @{$searchOUTER{$innerKey}{$innerVal}}, $outerKey;
	}
}

print "Outer Keys with IN1 eq I1 are @{$searchOUTER{IN1}{I1}}";

# Outputs:
# Outer Keys with IN1 eq I1 are OUT2 OUT1
 
Thanks all! As it turns out, I posed the question a little incorrectly, but your responses were invaluable in fixing my real problem! Thanks so much!!!!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top