34

I have this code

foreach my $key (keys %ad_grp) {

    # Do something
}

which works.

How would the same look like, if I don't have %ad_grp, but a reference, $ad_grp_ref, to the hash?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sandra Schlichting
  • 25,050
  • 33
  • 110
  • 162
  • Possible duplicate of [What's the safest way to iterate through the keys of a Perl hash?](https://stackoverflow.com/questions/3033/whats-the-safest-way-to-iterate-through-the-keys-of-a-perl-hash) – Ronak Shah Nov 13 '17 at 09:20

4 Answers4

71
foreach my $key (keys %$ad_grp_ref) {
    ...
}

Perl::Critic and daxim recommend the style

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

out of concerns for readability and maintenance (so that you don't need to think hard about what to change when you need to use %{ $ad_grp_obj[3]->get_ref() } instead of %{ $ad_grp_ref })

mob
  • 117,087
  • 18
  • 149
  • 283
  • 8
    You'd get more upvotes from me if you taught better style: [`keys %{ $ad_grp_ref }`](http://p3rl.org/Perl::Critic::Policy::References::ProhibitDoubleSigils) – daxim Mar 09 '11 at 17:09
  • 10
    that's not better, that's worse. also, http://perlmonks.org/?node=References+quick+reference can be very helpful – ysth Mar 09 '11 at 17:52
  • 5
    I fully agree with ysth, there's no reason to make an expression more complicated than it needs to be. – Eric Strom Mar 09 '11 at 18:24
  • 6
    `keys %$ad_grp_ref` is more readable, especially when surrounded by other circumfix operators. – friedo Mar 09 '11 at 18:42
  • As you can see, Sandra, There's More Than One Way To Do It. – mob Mar 09 '11 at 20:27
8

In Perl 5.14 (it works in now in Perl 5.13), we'll be able to just use keys on the hash reference

use v5.13.7;

foreach my $key (keys $ad_grp_ref) {
    ...
}
oylenshpeegul
  • 3,404
  • 1
  • 18
  • 18
  • you will need `use 5.14.0` or the like to be sure that your script doesn't attempt to run on Perl versions too old to use this syntax (or whatever 5.13.X this is allowed in of course). – Joel Berger Mar 10 '11 at 03:06
  • Good point, I should have put that right in the code sample. Amended. – oylenshpeegul Mar 10 '11 at 11:58
  • 6
    `Experimental keys on scalar is now forbidden`. This feature was removed in 5.22. (ish) –  Jan 16 '19 at 02:35
5

As others have stated, you have to dereference the reference. The keys function requires that its argument starts with a %:

My preference:

foreach my $key (keys %{$ad_grp_ref}) {

According to Conway:

foreach my $key (keys %{ $ad_grp_ref }) {

Guess who you should listen to...

You might want to read through the Perl Reference Documentation.

If you find yourself doing a lot of stuff with references to hashes and hashes of lists and lists of hashes, you might want to start thinking about using Object Oriented Perl. There's a lot of nice little tutorials in the Perl documentation.

David W.
  • 105,218
  • 39
  • 216
  • 337
4

With Perl 5.20 the new answer is:

foreach my $key (keys $ad_grp_ref->%*) {

(which has the advantage of transparently working with more complicated expressions:

foreach my $key (keys $ad_grp_obj[3]->get_ref()->%*) {

etc.)

See perlref for the full documentation.

Note: in Perl version 5.20 and 5.22, this syntax is considered experimental, so you need

use feature 'postderef';
no warnings 'experimental::postderef';

at the top of any file that uses it. Perl 5.24 and later don't require any pragmas for this feature.

Jonathan Cast
  • 4,569
  • 19
  • 34