Hashes
## Learning Objectives
- Create and manipulate hashes
- Use hash functions (keys, values, each)
- Check existence and delete entries
- Work with hash slices
- Understand hash internals
## Hash Basics
### Creating Hashes
```perl
use strict;
use warnings;
my %empty;
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
# => is fat comma, quotes optional for valid identifiers
```
### Accessing Elements
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
print $person{name}; # "Alice"
print $person{age}; # 30
# Modify
$person{age} = 31;
$person{email} = "alice@example.com";
```
### Hash from Arrays
```perl
my @keys = ("name", "age", "city");
my @values = ("Alice", 30, "Boston");
my %person = @keys; # Wrong! Creates (name, age, city, @values)
my %person = (@keys, @values); # Correct
```
### Hash from List
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
# Or using list directly
my %data = ("key1", "value1", "key2", "value2");
```
## Hash Functions
### keys
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
my @k = keys %person; # ("name", "age", "city")
# Iterate over keys
foreach my $key (keys %person) {
print "$key: $person{$key}\n";
}
```
### values
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
my @v = values %person; # ("Alice", 30, "Boston")
```
### each
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
while (my ($key, $value) = each %person) {
print "$key => $value\n";
}
```
### Iteration Order
```perl
use strict;
use warnings;
my %nums = (one => 1, two => 2, three => 3);
# Order not guaranteed (but consistent within program)
foreach my $key (keys %nums) {
print "$key => $nums{$key}\n";
}
```
## Existence and Deletion
### exists
```perl
my %person = (
name => "Alice",
age => 30,
);
if (exists $person{name}) {
print "Name exists\n";
}
if (!exists $person{email}) {
print "No email\n";
}
```
### delete
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
delete $person{age}; # Remove age
print $person{age}; # undef
# Safe delete
delete $person{$_} for qw(name age city);
```
### Defined Check
```perl
my %person = (
name => "Alice",
age => 30,
email => undef,
);
print defined $person{name}; # true
print defined $person{email}; # false (even though key exists)
print defined $person{nonexistent}; # false
```
## Hash Size
```perl
my %person = (
name => "Alice",
age => 30,
city => "Boston",
);
my $count = scalar keys %person; # 3
print "Hash has $count entries\n";
# Empty check
if (keys %person == 0) {
print "Hash is empty\n";
}
```
## Hash Sorting
### Sort by Keys
```perl
my %scores = (
bob => 87,
alice => 95,
carol => 92,
);
foreach my $name (sort keys %scores) {
print "$name: $scores{$name}\n";
}
```
### Sort by Values
```perl
foreach my $name (sort { $scores{$a} <=> $scores{$b} } keys %scores) {
print "$name: $scores{$name}\n";
}
# Reverse order
foreach my $name (sort { $scores{$b} <=> $scores{$a} } keys %scores) {
print "$name: $scores{$name}\n";
}
```
## Hash Slices
### Basic Slice
```perl
my %person = (
first => "Alice",
last => "Smith",
age => 30,
);
# Multiple access
my ($first, $last) = @person{qw(first last)};
# Multiple assignment
@person{qw(first, last)} = ("Bob", "Jones");
```
### Slice for Initialization
```perl
my @fields = qw(name age city);
my @vals = ("Alice", 30, "Boston");
my %person;
@person{@fields} = @vals;
```
## Hash References
### Creating References
```perl
my %person = (
name => "Alice",
age => 30,
);
my $ref = \%person;
# Access via reference
print $ref->{name}; # "Alice"
```
### Anonymous Hash
```perl
my $person = {
name => "Alice",
age => 30,
};
print $person->{name}; # "Alice"
```
### Dereferencing
```perl
my $ref = { a => 1, b => 2 };
my %hash = %$ref;
# Or with braces if ambiguous
my %hash = %{ $ref };
```
## Nested Hashes
```perl
use strict;
use warnings;
my %company = (
engineering => {
alice => { name => "Alice", title => "Engineer" },
bob => { name => "Bob", title => "Manager" },
},
sales => {
carol => { name => "Carol", title => "Sales Rep" },
},
);
print $company{engineering}{alice}{title}; # "Engineer"
# Reference style
my $eng = $company{engineering};
print $eng->{alice}{name}; # "Alice"
```
## Default Values
### Autovivification
```perl
my %counts;
$counts{apple}++; # Creates apple => 1 (not undef error)
$counts{banana} += 5; # Creates banana => 5
# Without autovivification
my %safe;
if (exists $safe{key}) {
$safe{key}++;
} else {
$safe{key} = 1;
}
```
### defined-or operator
```perl
my %hash = (count => 0);
$hash{count} //= 10; # Won't change (0 is defined)
$hash{new} //= 10; # Sets new => 10
# vs || which uses truthiness
$hash{count} ||= 10; # Would change 0 to 10!
```
## Hash as Set
```perl
# Using hash for unique values
my %seen;
my @unique;
foreach my $item (@items) {
if (!$seen{$item}++) {
push @unique, $item;
}
}
# Simple set operations
my %set1 = map { $_ => 1 } qw(a b c);
my %set2 = map { $_ => 1 } qw(b c d);
# Union
my %union = (%set1, %set2);
# Intersection
my @intersection = grep { $set1{$_} && $set2{$_} } (keys %set1, keys %set2);
```
## Useful Hash Tricks
### Reversing Hash
```perl
my %original = (a => 1, b => 2, c => 3);
my %reversed = reverse %original;
print "$reversed{1}\n"; # "a"
```
### Counting Occurrences
```perl
my @words = qw(apple banana apple cherry banana apple);
my %count;
foreach my $word (@words) {
$count{$word}++;
}
print $count{apple}; # 3
```
### Inverting Hash
```perl
my %正向 = (a => 1, b => 2, c => 3);
my %反向 = reverse %正向;
print "$反向{1}\n"; # "a"
```
## Summary
- Hashes created with `%` sigil and key-value pairs
- Use `=>` (fat comma) for readability
- `keys`, `values`, `each` for iteration
- `exists` checks key existence
- `delete` removes entry
- Hash slices access multiple values
- References use `->` for access
- Hashes don't preserve order (pre 5.38)
- Useful for counting, unique values, lookup tables
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →