Hashes

Perl Fundamentals — Hashes
Perl Fundamentals
Course 1 · Chapter 4 · Hashes

🗂️ Hashes

The third and final sigil this course covers directly. A hash is Perl's key-value store — the same role a Python dict or JavaScript object plays — and it follows the exact same sigil-switching rule Chapter 3 established for arrays.

🏷️ The % Sigil

my %ages = ( "Ada" => 28, "Grace" => 85, );

=> (the "fat comma") is functionally identical to a plain comma — it's used here purely for readability, visually pairing each key with its value. As a bonus, a bareword immediately to its left is automatically quoted, so Ada => 28 works exactly like "Ada" => 28.

Accessing a single value uses curly braces and, once again, the $ sigil — not %:

say $ages{"Ada"}; # 28 — one scalar value out of the hash, so $

This is the exact same rule from Chapter 3's $fruits[0], just with curly braces instead of square brackets: %ages is the whole hash, $ages{"Ada"} is one scalar value pulled out of it.

🛠️ Common Hash Operations

$ages{"Alan"} = 41; # add a new key, or overwrite an existing one if (exists $ages{"Ada"}) { # checks whether the KEY exists — even if its value is 0 or undef say "Found Ada"; } delete $ages{"Ada"}; # removes the key entirely my @names = keys %ages; # an array of every key my @years = values %ages; # an array of every value
⚠ exists Checks the Key, Not the Value's Truthiness

if ($ages{"Bob"}) and if (exists $ages{"Bob"}) are genuinely different questions. If $ages{"Bob"} is 0 (a valid age for a newborn, technically) or undef, the first check is false even though the key is really there — exists answers "is this key present at all," independent of whatever value it happens to hold.

🔁 Iterating Hashes

foreach my $name (keys %ages) { say "$name is $ages{$name}"; }

foreach ... keys %hash is the standard, idiomatic way to iterate — loop over the keys, look up each value as needed. Perl also has an each function (while (my ($name, $age) = each %ages) { ... }) that returns key/value pairs one at a time, but it has real gotchas if the hash is modified mid-loop — keys-based iteration is the safer, more common idiom in real code.

⚠ Hash Order Is Not Guaranteed

Unlike Python 3.7+ dictionaries (which guarantee insertion order), Perl hashes have no guaranteed order at all — keys %ages can return the keys in a different order between runs, or even between two calls in the same run in older Perl versions. If a specific, predictable order matters, sort explicitly: foreach my $name (sort keys %ages).

🔧 A Worked Example — Word Frequency Count

my @words = split(' ', "the cat sat on the mat the cat ran"); my %counts; foreach my $word (@words) { $counts{$word}++; # auto-vivifies to 0 the first time, then increments } foreach my $word (sort keys %counts) { say "$word: $counts{$word}"; } # cat: 2 # mat: 1 # on: 1 # ran: 1 # sat: 1 # the: 3

$counts{$word}++ works even the very first time a given word is seen — an unset hash value auto-vivifies to undef, which ++ treats as 0 before incrementing, so no separate "does this key exist yet?" check is needed first.

Hashes: Perl vs. Python

Perl hashes and Python dicts serve the identical role — a Python developer will recognize the concept instantly. The differences are the same two threads running through this whole course: the sigil switches from % to $ the moment you access one value ($hash{key}, vs. Python's uniform my_dict[key]), and — genuinely worth remembering — Perl hashes have never guaranteed any particular order, where Python's dicts have guaranteed insertion order since 3.7.

% vs $

%hash is the whole hash; $hash{key} is one scalar value.

exists vs truthiness

exists $hash{key} checks presence, independent of the value itself.

keys / values

Return arrays — unordered by default, sort explicitly when order matters.

Auto-vivification

$hash{key}++ works even on a key that's never been set yet.

💻 Coding Challenges

Challenge 1: Build and Query a Hash

Declare a hash mapping 3 countries to their capital cities. Print one capital by looking it up directly, then print "Found" or "Not found" for a country that isn't in the hash, using exists.

→ Solution

Challenge 2: Sorted Iteration

Given a hash of 4 people mapped to their ages, print each "Name: Age" pair sorted alphabetically by name, using sort keys.

→ Solution

Challenge 3: exists vs Truthiness

Given my %inventory = ("apples" => 5, "bananas" => 0);, show that if ($inventory{"bananas"}) and if (exists $inventory{"bananas"}) behave differently, and explain why in one sentence.

→ Solution

🎯 What's Next

Next chapter: Control Flow & Operators — if/unless, while/until, for/foreach, and Perl's postfix conditionals.