Complex Data Structures
use v5.36;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Indent = 1;
# Array of arrays (2D matrix)
my @matrix = ([1, 2, 3], [4, 5, 6], [7, 8, 9]);
say $matrix[1][2]; # 6 (arrows between subscripts are optional)
for my $row (@matrix) { say join ' ', @$row }
# Hash of arrays
my %hobbies = (ana => ['chess', 'go'], bo => ['tennis']);
push @{ $hobbies{ana} }, 'piano';
push $hobbies{cy}->@*, 'swim'; # autovivification creates $hobbies{cy} = []
# Array of hashes
my @users = (
{ name => 'Ana', age => 30, roles => ['admin', 'dev'] },
{ name => 'Bo', age => 25, roles => ['dev'] },
);
say $users[0]{roles}[1]; # dev
my @admins = grep { grep { $_ eq 'admin' } @{ $_->{roles} } } @users;
say $_->{name} for sort { $a->{age} <=> $b->{age} } @users;
# Hash of hashes
my %config = (
database => { host => 'localhost', port => 5432 },
cache => { host => 'redis', port => 6379 },
);
for my $service (sort keys %config) {
say "$service: $config{$service}{host}:$config{$service}{port}";
}
# Deeply nested data (like JSON)
my $data = {
company => 'Acme',
departments => [
{ name => 'R&D', employees => [ { name => 'A
…13.1 Autovivification
Accessing a nested element that doesn't exist creates the intermediate structures automatically:
my %h;
$h{a}{b}{c} = 1; # creates $h{a} = {}, $h{a}{b} = {}
if (exists $h{x}{y}) { } # side effect: creates $h{x} = {}!
if (exists $h{x} && exists $h{x}{y}) { } # safe check
no autovivification; # CPAN pragma to disable it13.2 Traversing Arbitrary Structures
sub walk($node, $depth = 0) {
my $pad = ' ' x $depth;
if (ref $node eq 'HASH') {
for my $k (sort keys %$node) { say "$pad$k:"; walk($node->{$k}, $depth + 1) }
} elsif (ref $node eq 'ARRAY') {
walk($_, $depth + 1) for @$node;
} else {
say $pad, $node // 'undef';
}
}
walk($data);