What's the safest way to iterate through the keys of a Perl hash?

If I have a Perl hash with a bunch of (key, value) pairs, what is the preferred method of iterating through all the keys? I have heard that using each may in some way have unintended side effects. So, is that true, and is one of the two following methods best, or is there a better way?

# Method 1
while (my ($key, $value) = each(%hash)) {
    # Something
}

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}

Answers


The rule of thumb is to use the function most suited to your needs.

If you just want the keys and do not plan to ever read any of the values, use keys():

foreach my $key (keys %hash) { ... }

If you just want the values, use values():

foreach my $val (values %hash) { ... }

If you need the keys and the values, use each():

keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }

If you plan to change the keys of the hash in any way except for deleting the current key during the iteration, then you must not use each(). For example, this code to create a new set of uppercase keys with doubled values works fine using keys():

%h = (a => 1, b => 2);

foreach my $k (keys %h)
{
  $h{uc $k} = $h{$k} * 2;
}

producing the expected resulting hash:

(a => 1, A => 2, b => 2, B => 4)

But using each() to do the same thing:

%h = (a => 1, b => 2);

keys %h;
while(my($k, $v) = each %h)
{
  $h{uc $k} = $h{$k} * 2; # BAD IDEA!
}

produces incorrect results in hard-to-predict ways. For example:

(a => 1, A => 2, b => 2, B => 8)

This, however, is safe:

keys %h;
while(my($k, $v) = each %h)
{
  if(...)
  {
    delete $h{$k}; # This is safe
  }
}

All of this is described in the perl documentation:

% perldoc -f keys
% perldoc -f each

Need Your Help

RedirectStandardOutput Doesn't Fire Until Console Process Finishes

c# winforms visual-studio console-application outputstream

I have a strange issue that has come up. I have written a windows form app in C# using Visual Studio 2012/13. My app opens a console application and captures the standard and error output from it a...

How to make Django ManyToMany relationships explicit on the receiving model's end

python django django-models

Relationships, particularly ManyToMany, in Django have always bothered me somewhat. In particular, since the relationship is only defined in one of the models, you can't tell from looking at the p...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.