home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

Book HomeLearning Perl, 3rd EditionSearch this book

5.3. Hash Functions

Naturally, there are some useful functions that can work on an entire hash at once.

5.3.1. The keys and values Functions

The keys function yields a list of all the current keys in a hash, while 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.[131]

[131]Of course, 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. So no normal programmer would do that.

In a scalar context, these functions give the number of elements (key-value pairs) in the hash. They do this quite efficiently, without having to visit each element of the hash:

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

Once in a long while, you'll see that someone has used a hash as a Boolean (true/false) expression, something 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.[132] So, it's just saying, "if the hash is not empty...". But this is a pretty rare construct, as such things go.

[132]The actual 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.

5.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.[133] On each evaluation of this function for the same array, 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.

[133]The other usual 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, something 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; let's 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.[134]) 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.

[134]Since each hash has its own private iterator, loops using each may be nested, as long as they are iterating over different hashes. And, as long as we're already in a footnote, we may as well tell you: it's unlikely you'll ever need to do so, but 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. Now, when Perl evaluates each %hash, there are no more key-value pairs available. So, each has to return an empty list.[135] The empty list is assigned to ($key, $value), so $key gets undef, and $value also gets undef.

[135]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, incidentally; the "natural" order of the hash.) If you need to go through the hash in order, simply 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 15, "Strings and Sorting".



Library Navigation Links

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











??????????????@Mail.ru