how on earth do I iterate through a hash?and then you see the each() method. This gives rise to the following code:
while( my ($key, $value) = each(%my_hash)) {
print $key, '->', $value, "\n";
}
This all seems fine & dandy until we want to do something like this:
our %my_hash = (a=>1,b=>2);
my @elements = get_from_somewhere();
print "Starting\n";
OUTERLOOP: foreach my $el (@elements) {
while( my $key, $value) = each(%my_hash)) {
print $key, "\n";
if($key eq 'a') {
last OUTERLOOP;
}
}
}
Still seems okay right? Wrong! See the problem here comes from iteration of the EntrySet belonging to the hash & not to another data structure so on multiple invocations of this code the iteration of the map continues from where it left-off. So if the elements from the hash are returned in the order a,b & we execute it twice you will see:
Starting
a
Starting
b
a
To get to the correct expected output you need:
our %my_hash = (a=>1,b=>2);
my @elements = get_from_somewhere();
print "Starting\n";
OUTERLOOP: foreach my $el (@elements) {
foreach my $key (keys %my_hash) {
my $value = $my_hash{$key};
print $key, "\n";
if($key eq 'a') {
last OUTERLOOP;
}
}
}
So what's the solution? Well if I said never use each then I would be stupid & wrong. each makes sense. What I would recommend is if you might break out of a loop using a data structure where you may require early termination of a hash structure which is persistent between calls then do not use each. Or use one of the Iterator functions/modules in CPAN to provide a more Java like method of access to hashes; but then that wouldn't be Perl :).