A slice of hash

(originally posted 2009-10-20)

I used to like Perl. The past few months using it as my main language, I grew to really like it a lot. What had me fall head over heels in love, what inspired me to start this new blog series: hash slices. Anyone who’s been around Perl at all knows hashes (i.e. associative arrays, to use the behavioral description rather than the implementation description). They are a core feature that set it apart fairly early on as a force to be reckoned with, and has been emulated numerous times due to it’s simplicity and power. But addressing multiple elements of an associative array requires some sort of loop, right? Not so in Perl. List assignments are a fairly well-known aspect of Perl. But with a hash slice, you can treat a set of hash elements exactly as you would a list.

You’ve probably come across array slices before, though you may not have recognized them as such:

@foo[1..5]
@bar[2,4,6]

These can be used pretty much anywhere a regular list could, even as an lvalue. A hash slice produces much the same animal, though it comes of different parentage. The key syntax for referring to a hash slice is analogous:

@hash{list_of_keys}

@list_of_keys could also be replaced by a literal list, a function returning a list, a de-referenced array reference, etc. In other words, you tell the parser that you want a list of hash elements and just supply a list of keys. That’s interesting, but it gets insanely beautiful when you do things like assigning to a hash slice:

# Assign sequential values to a bunch of hash elements
@my_hash{qw(a b c d)} = 1..4;
# Copy all elements of hash_b whose key has a 'g' in it into hash_a, leaving other elements of hash_a intact
@hash_a{@tmp} = @hash_b{@tmp = sort grep {/g/} keys %hash_b};
# Assign the value 1 to all elements of the hash referenced by $hashref, whose keys are in the array true_keys
@{$hashref}{@true_keys} = (1) x scalar(@true_keys);

To accomplish these same things you would have had to do things like:

@my_arr = qw(a b c d);
foreach (0..$#my_arr) {
$my_hash{$my_arr[$_]} = $_ + 1;
}
foreach (grep {/g/} sort keys %hash_b) {
$hash_a{$_} = $hash_b{$_};
}
foreach (@true_keys) {
$hashref->{$_} = 1;
}

Or even more unwieldy:

$my_hash{a} = 1;
$my_hash{b} = 2;
$my_hash{c} = 3;
$my_hash{d} = 4;
...

The minute I discovered hash slices, I was able to refactor away dozens of lines of code, and make things in most circumstances easier to understand and harder to break. Once you become familiar with the syntax, it can be much easier to discern the intention of a single line of code than a loop, or god forbid a series of assignments.

So let’s get slicin’ and dicin’ people!

Leave a Reply

Your email address will not be published. Required fields are marked *