Hashes with Multiple Values per Key (Perl Cookbook, 2nd Edition)

## 5.8. Hashes with Multiple Values per Key

### 5.8.1. Problem

You want to store more than one value for each key.

### 5.8.2. Solution

Store an array reference in `$hash{$key}`, then put the values into the referenced array.

### 5.8.3. Discussion

You can store only scalar values in a hash. References, however, are scalars. This solves the problem of storing multiple values for one key by making `$hash{$key}` a reference to an array containing values for `$key`. The normal hash operations—insertion, deletion, iteration, and testing for existence—can now be written in terms of array operations like `push`, `splice`, and `foreach`.

This code shows simple insertion into the hash. It processes the output of who(1) on Unix machines and outputs a terse listing of users and the ttys they're logged in on:

>     %ttys = ( );

>     open(WHO, "who|")                   or die "can't open who: $!";
>     while (<WHO>) {
>         ($user, $tty) = split;
>         push( @{$ttys{$user}}, $tty );
>     }

>     foreach $user (sort keys %ttys) {
>         print "$user: @{$ttys{$user}}\n";
>     }

The heart of the code is the `push` line, the multivalued version of `$ttys{$user}` `=` `$tty`. The first time through, that hash value is undefined, so Perl automatically allocates a new anonymous hash and stores its reference in that value so that the `push` can succeed. This is called autovivification, and is explained more in Chapter 11.

We interpolate all the tty names in the `print` line with `@{$ttys{$user}}`. We'd loop over the anonymous array if, for instance, we wanted to print the owner of each tty:

>     foreach $user (sort keys %ttys) {
>         print "$user: ", scalar( @{$ttys{$user}} ), " ttys.\n";
>         foreach $tty (sort @{$ttys{$user}}) {
>             @stat = stat("/dev/$tty");
>             $user = @stat ? ( getpwuid($stat[4]) )[0] : "(not available)";
>             print "\t$tty (owned by $user)\n";
>         }
>     }

The `exists` function can have two meanings: "Is there at least one value for this key?" and "Does this value exist for this key?" Implementing the second approach requires searching the array for the value. The `delete` function and the first sense of `exists` are interrelated: if we can guarantee that no anonymous array is ever empty, we can use the built-in `exists`. We ensure that no anonymous array is ever empty by checking for that after deleting an element.

>     sub multihash_delete {
>         my ($hash, $key, $value) = @_;
>         my $i;

>         return unless ref( $hash->{$key} );
>         for ($i = 0; $i < @{ $hash->{$key} }; $i++) {
>             if ($hash->{$key}->[$i] eq $value) {
>                 splice( @{$hash->{$key}}, $i, 1);
>                 last;
>             }
>         }

>         delete $hash->{$key} unless @{$hash->{$key}};
>     }

An alternative approach to multivalued hashes is given in Chapter 13, implemented as tied normal hashes.

### 5.8.4. See Also

The `splice`, `delete`, `push`, `foreach`, and `exists` functions in perlfunc(1) and Chapter 29 of Programming Perl; Recipe 11.1; we cover ties in Recipe 13.15

Copyright © 2003 O'Reilly & Associates. All rights reserved.