# Recipe 5.9 Inverting a Hash

#### 5.9.1 Problem

Hashes map keys to values. You have a hash and a value whose corresponding key you want to find.

#### 5.9.2 Solution

Use reverse to create an inverted hash whose values are the original hash's keys and vice versa.

```# %LOOKUP maps keys to values
%REVERSE = reverse %LOOKUP;```

#### 5.9.3 Discussion

This technique uses the list equivalence of hashes mentioned in the introduction. In list context, reverse treats %LOOKUP as a list and reverses the order of its elements. The significant property of a hash treated as a list is that the list elements come in associated pairs: the first element is the key; the second, the value. When you reverse such a list, the first element is now the value, and the second the key. Treating this list as a hash results in a hash whose values are the keys of the original hash and vice versa.

Here's an example:

```%surname = ( "Mickey" => "Mantle", "Babe" => "Ruth" );
%first_name = reverse %surname;
print \$first_name{"Mantle"}, "\n";
Mickey```

When we treat %surname as a list, it becomes:

`("Mickey", "Mantle", "Babe", "Ruth")`

(or maybe ("Babe", "Ruth", "Mickey", "Mantle") because we can't predict the order). Reversing this list gives us:

`("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 foodfind. If you give it a food name, it'll tell you the color of that food. If you give it a color, it'll tell you a food of that color.

##### 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 "Lemon" and "Banana" do in the color example), then the inverted hash will only have one (which is dependent on the hashing order, and you shouldn't try to predict it). This is because hashes have, by Perl definition, unique keys.

If you want to invert a hash with non-unique values, you must use the techniques shown in Recipe 5.8. 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";
Banana Lemon were yellow foods.```

This also lets us change the foodfind program to handle colors represented by more than one food. For instance, foodfind yellow reports bananas and lemons.

If any values in the original hash were references instead of strings or numbers, the inverted hash poses a problem because references don't work well as hash keysunless you use the Tie::RefHash module described in Recipe 5.13.

The reverse function in perlfunc(1) and in Chapter 29 of Programming Perl; Recipe 13.15

 Chapter 1. Strings
 Chapter 2. Numbers
 Chapter 3. Dates and Times
 Chapter 4. Arrays
 Chapter 6. Pattern Matching
 Chapter 7. File Access
 Chapter 8. File Contents
 Chapter 9. Directories
 Chapter 10. Subroutines
 Chapter 11. References and Records
 Chapter 12. Packages, Libraries, and Modules
 Chapter 13. Classes, Objects, and Ties
 Chapter 14. Database Access
 Chapter 15. Interactivity
 Chapter 16. Process Management and Communication
 Chapter 17. Sockets
 Chapter 18. Internet Services
 Chapter 19. CGI Programming
 Chapter 20. Web Automation
 Chapter 21. mod_perl
 Chapter 22. XML