Perl Language Variables Hashes


Example

Hashes can be understood as lookup-tables. You can access its contents by specifiying a key for each of them. Keys must be strings. If they're not, they will be converted to strings.

If you give the hash simply a known key, it will serve you its value.

# Elements are in (key, value, key, value) sequence
my %inhabitants_of = ("London", 8674000, "Paris", 2244000);

# You can save some typing and gain in clarity by using the "fat comma"
# syntactical sugar. It behaves like a comma and quotes what's on the left.
my %translations_of_hello = (spanish => 'Hola', german => 'Hallo', swedish => 'Hej'); 

In the following example, note the brackets and sigil: you access an element of %hash using $hash{key} because the value you want is a scalar. Some consider it good practice to quote the key while others find this style visually noisy. Quoting is only required for keys that could be mistaken for expressions like $hash{'some-key'}

my $greeting = $translations_of_hello{'spanish'};

While Perl by default will try to use barewords as strings, + modifier can also be used to indicate to Perl that key should not be interpolated but executed with result of execution being used as a key:

my %employee = ( name => 'John Doe', shift => 'night' );
# this example will print 'night'
print $employee{shift}; 

# but this one will execute [shift][1], extracting first element from @_,
# and use result as a key
print $employee{+shift};

Like with arrays, you can access multiple hash elements at the same time. This is called a hash slice. The resulting value is a list, so use the @ sigil:

my @words = @translations_of_hello{'spanish', 'german'}; # ('Hola', 'Hallo')

Iterate over the keys of an hash with keys keys will return items in a random order. Combine with sort if you wish.

for my $lang (sort keys %translations_of_hello) {
  say $translations_of_hello{$lang};
}

If you do not actually need the keys like in the previous example, values returns the hash's values directly:

for my $translation (values %translations_of_hello) {
  say $translation;
}

You can also use a while loop with each to iterate over the hash. This way, you will get both the key and the value at the same time, without a separate value lookup. Its use is however discouraged, as each can break in mistifying ways.

# DISCOURAGED
while (my ($lang, $translation) = each %translations_of_hello) {
  say $translation;
}

Access to unset elements returns undef, not an error:

my $italian = $translations_of_hello{'italian'}; # undef

map and list flattening can be used to create hashes out of arrays. This is a popular way to create a 'set' of values, e.g. to quickly check whether a value is in @elems. This operation usually takes O(n) time (i.e. proportional to the number of elements) but can be done in constant time (O(1)) by turning the list into a hash:

@elems = qw(x y x z t);
my %set = map { $_ => 1 } @elems;   # (x, 1, y, 1, t, 1)
my $y_membership = $set{'y'};       # 1
my $w_membership = $set{'w'};       # undef

This requires some explanation. The contents of @elems get read into a list, which is processed by map. map accepts a code block that gets called for each value of its input list; the value of the element is available for use in $_. Our code block returns two list elements for each input element: $_, the input element, and 1, just some value. Once you account for list flattening, the outcome is that map { $_ => 1 } @elems turns qw(x y x z t) into (x => 1, y => 1, x => 1, z => 1, t => 1).

As those elements get assigned into the hash, odd elements become hash keys and even elements become hash values. When a key is specified multiple times in a list to be assigned to a hash, the last value wins. This effectively discards duplicates.

A faster way to turn a list into a hash uses assignment to a hash slice. It uses the x operator to multiply the single-element list (1) by the size of @elems, so there is a 1 value for each of the keys in the slice on the left hand side:

@elems = qw(x y x z t);
my %set;
@set{@elems} = (1) x @elems;

The following application of hashes also exploits the fact that hashes and lists can often be used interchangeably to implement named function args:

sub hash_args {
  my %args = @_;
  my %defaults = (foo => 1, bar => 0);
  my %overrides = (__unsafe => 0);
  my %settings = (%defaults, %args, %overrides);
}

# This function can then be called like this:
hash_args(foo => 5, bar => 3); # (foo => 5, bar => 3, __unsafe ==> 0)
hash_args();                   # (foo => 1, bar => 0, __unsafe ==> 0)
hash_args(__unsafe => 1)       # (foo => 1, bar => 0, __unsafe ==> 0)

When used as booleans, hashes are true if they are not empty.