4

How do I set a list of scalars from a perl hash?

use strict;
my $my_hash = { field1=>'val1', field2=>'val2', field3=>'val3', };
my ($field1,$field2,$field3) = %{$my_hash}{qw(field1 field2 field3)};

print "field1=$field1\nfield2=$field2\nfield3=$field3\n";
null
  • 889
  • 1
  • 13
  • 24

2 Answers2

5

You're looking for a hash slice which in your case would look like this:

my ($field1,$field2,$field3) = @{$my_hash}{qw(field1 field2 field3)};

or like this:

my ($field1,$field2,$field3) = @$my_hash{qw(field1 field2 field3)};

If we simplify things so that you're working with a straight hash rather than hash-ref, we can remove some of the noise and the syntax will look a bit clearer:

my %my_hash = ( field1=>'val1', field2=>'val2', field3=>'val3' );
my ($field1, $field2, $field3) = @my_hash{  qw(field1 field2 field3)  };
# we want an array/list ---------^       ^  ^
# but my_hash is a hash -----------------/  |
# and we want these keys (in this order) ---/
# so we use a qw()-array

Then we can get to your $my_hash hash-ref version by replacing the hash with a hash-ref in the usual way.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Using `@` when wanting an array/list is wrong. That doesn't always work. – ikegami Dec 01 '12 at 06:59
  • @ikegami: That's more of mnemonic than anything else here. You're welcome to offer a better explanation of the syntax if you'd like. `@` doesn't mean "array", except when it does; `{` doesn't mean "hash", except when it does; a cigar is just a cigar, except when it isn't. – mu is too short Dec 01 '12 at 07:13
  • `%` gets a list from a hash just as much as `@` does. Furthermore, `@` is only used for two of three types of slices. Whichever way you look at it, it's not a useful "mnemonic" if it's wrong half the time. Instead of offering wrong/misleading advice, tell him the syntax for a hash slice, then show him how to apply it to a hash ref instead of a hash. – ikegami Dec 01 '12 at 08:44
0

The following works just fine:

#!/usr/bin/perl
use warnings;
use strict;
my $my_hash = { field1=>'val1', field2=>'val2', field3=>'val3', };
my ($field1,$field2,$field3) = (values %{$my_hash});
print "field1=$field1\nfield2=$field2\nfield3=$field3\n";

but, see the following for why it won't work well:

Is Perl guaranteed to return consistently-ordered hash keys?

An example of this going wrong is as follows:

my $my_hash = { field1=>'val1', blah=>'val1.1', field2=>'val2', field3=>'val3', };
my ($field1,$field2, $blah,$field3) = (sort values %{$my_hash});
print "field1=$field1\nfield2=$field2\nblah=$blah\nfield3=$field3\n";

the output is:

field1=val1
field2=val1.1
blah=val2
field3=val3

Note that the value of $field1 is wrong here. As "mu is too short" has already noted a Hash Slice is the way to go here to make sure the ordering is what you expect, and don't forget to use warnings on all your code.

Community
  • 1
  • 1
Harry
  • 11,298
  • 1
  • 29
  • 43
  • I thought the same thing, but I think he is looking for specific keys. – jordanm Dec 01 '12 at 06:45
  • 5
    ["When called on a hash, the values are returned in an apparently random order."](http://perldoc.perl.org/functions/values.html) I don't think you can depend on `values %h` returning the values in any particular order. – mu is too short Dec 01 '12 at 06:47
  • Thank you for your response. I wanted to guarantee the scalars are set to the values in the has that correspond the scalar names. – null Dec 01 '12 at 07:01