5.8. Inverting a HashProblemHashes map keys to values. You have a hash and a value for which you want to find the corresponding key. Solution
Use # %LOOKUP maps keys to values %REVERSE = reverse %LOOKUP; Discussion
This technique uses the list equivalence of hashes mentioned in the introduction. In list context, Here's an example:
%surname = ( "Mickey" => "Mantle", "Babe" => "Ruth" );
%first_name = reverse %surname;
print $first_name{"Mantle"}, "\n";
When we treat
("Mickey", "Mantle", "Babe", "Ruth")
(or maybe
("Ruth", "Babe", "Mantle", "Mickey")
When we treat this list as a hash, it becomes:
("Ruth" => "Babe", "Mantle" => "Mickey")
Now instead of turning first names into surnames, it turns surnames into first names.
Example 5.2
is a program called Example 5.2: foodfind
#!/usr/bin/perl -w
# foodfind - find match for food or color
$given = shift @ARGV or die "usage: foodfind food_or_color\n";
%color = (
"Apple" => "red",
"Banana" => "yellow",
"Lemon" => "yellow",
"Carrot" => "orange"
);
%food = reverse %color;
if (exists $color{$given}) {
print "$given is a food with color $color{$given}.\n";
}
if (exists $food{$given}) {
print "$food{$given} is a food with color $given.\n";
}
If two keys in the original hash have the same value (as If you want to invert a hash with non-unique values, you must use the techniques shown in Recipe 5.7 . That is, build up a hash whose values are a list of keys in the original hash:
# %food_color as per the introduction
while (($food,$color) = each(%food_color)) {
push(@{$foods_with_color{$color}}, $food);
}
print "@{$foods_with_color{yellow}} were yellow foods.\n";
This also lets us change the If any values in the original hash were references instead of just strings and numbers, the inverted hash poses a problem because references don't work well as hash keys unless you use the Tie::RefHash module described in Recipe 5.12 . See Also
The |
|