Приглашаем посетить
Хлебников (hlebnikov.lit-info.ru)

Section 6.3.  Hash Functions

Previous
Table of Contents
Next

6.3. Hash Functions

Some useful functions can work on an entire hash simultaneously.

6.3.1. The keys and values Functions

The keys function yields a list of all the keys in a hash, and the values function gives the corresponding values. If there are no elements to the hash, then either function returns an empty list:

    my %hash = ("a" => 1, "b" => 2, "c" => 3);
    my @k = keys %hash;
    my @v = values %hash;

So, @k will contain "a", "b", and "c", and @v will contain 1, 2, and 3 in some order. Remember, Perl doesn't maintain the order of elements in a hash. But, whatever order the keys are in, the values will be in the corresponding order: if "b" is last in the keys, 2 will be last in the values; if "c" is the first key, 3 will be the first value. That's true as long as you don't modify the hash between the request for the keys and the one for the values. If you add elements to the hash, Perl reserves the right to rearrange it as needed to keep the access quick.[*] In a scalar context, these functions give the number of elements (key/value pairs) in the hash. They do this efficiently without having to visit each element of the hash:

[*] If you started adding elements to the hash between keys and values, your list of values (or keys, whichever you did second) would have additional items, which would be tough to match up with the first list. No normal programmer would do that.

    my $count = keys %hash;  # gets 3, meaning three key/value pairs

Once in a while, you'll see that someone has used a hash as a Boolean (true/false) expression like this:

    if (%hash) {
      print "That was a true value!\n";
    }

That will be true if (and only if) the hash has at least one key/value pair.[Section 6.3.  Hash Functions] So, it's saying, "if the hash is not empty...." This is a rare construct, as such things go.

[Section 6.3.  Hash Functions] The result is an internal debugging string useful to the people who maintain Perl. It looks something like "4/16," but the value is guaranteed to be true when the hash is non-empty and false when it's empty, so the rest of us can still use it for that.

6.3.2. The each Function

If you wish to iterate over (that is, examine every element of) an entire hash, one of the usual ways is to use the each function, which returns a key/value pair as a two-element list.[Section 6.3.  Hash Functions] On each evaluation of this function for the same hash, the next successive key/value pair is returned, until all the elements have been accessed. When there are no more pairs, each returns an empty list.

[Section 6.3.  Hash Functions] Another way to iterate over an entire hash is to use foreach on a list of keys from the hash; we'll see that by the end of this section.

In practice, the only way to use each is in a while loop like this:

    while ( ($key, $value) = each %hash ) {
      print "$key => $value\n";
    }

There's a lot going on here. First, each %hash returns a key/value pair from the hash, as a two-element list; let's say that the key is "c" and the value is 3, so the list is ("c", 3). That list is assigned to the list ($key, $value), so $key becomes "c" and $value becomes 3.

But that list assignment is happening in the conditional expression of the while loop, which is a scalar context. (Specifically, it's a Boolean context looking for a true/false value, and a Boolean context is a particular kind of scalar context.) The value of a list assignment in a scalar context is the number of elements in the source list, 2, in this case. Since 2 is a true value, we enter the body of the loop and print the message c => 3.

The next time through the loop, each %hash gives a new key/value pair. Say it's ("a", 1) this time. (It knows to return a different pair than previously because it keeps track of where it is; in technical jargon, there's an iterator stored in with each hash.[*]) Those two items are stored into ($key, $value). Since the number of elements in the source list was again 2, a true value, the while condition is true, and the loop body runs again, telling us a => 1.

[*] Since each hash has its own private iterator, loops using each may be nested as long as they are iterating over different hashes. As long as we're in a footnote, we may as well tell you that you may reset the iterator of a hash by using the keys or values function on the hash. The iterator is also automatically reset if a new list is stored into the entire hash or if each has iterated through all of the items to the "end" of the hash. On the other hand, adding new key/value pairs to the hash while iterating over it is generally a bad idea since that won't necessarily reset the iterator. That's likely to confuse you, your maintenance programmer, and each as well.

We go one more time through the loop, and by now we know what to expect, so it's no surprise to see b => 2 appear in the output.

But we knew it couldn't go on forever. The next time Perl evaluates each %hash, no more key/value pairs are available, so each has to return an empty list.[Section 6.3.  Hash Functions] The empty list is assigned to ($key, $value), so $key gets undef, and $value also gets undef.

[Section 6.3.  Hash Functions] It's being used in list context, so it can't return undef to signal failure; that would be the one-element list (undef) instead of the empty (zero-element) list ( ).

But that hardly matters because the whole thing is being evaluated in the conditional expression of the while loop. The value of a list assignment in a scalar context is the number of elements in the source list; in this case, that's 0. Since 0 is a false value, the while loop is done, and execution continues with the rest of the program.

Of course, each returns the key/value pairs in a jumbled order. (It's the same order as keys and values would give, which is the "natural" order of the hash.) If you need to go through the hash in order, sort the keys, perhaps something like this:

    foreach $key (sort keys %hash) {
      $value = $hash{$key};
      print "$key => $value\n";
      # Or, we could have avoided the extra $value variable:
      #  print "$key => $hash{$key}\n";
    }

We'll see more about sorting hashes in Chapter 13.

    Previous
    Table of Contents
    Next