--- name: arrays of arrays --- # Arrays of arrays Perl arrays hold scalars, and scalars cannot directly contain other arrays. To build a two-dimensional array — a matrix, a grid, a table of rows — you store **references** to inner arrays as the outer array's elements. This chapter shows how. ## Building a matrix The most direct form uses anonymous array constructors (`[...]`, covered in detail in *Anonymous references*) so you don't have to name every inner array: ```perl my @m = ( [1, 2, 3], [4, 5, 6], [7, 8, 9], ); ``` `@m` has three elements. Each element is a scalar holding an array reference. There are four arrays in play: the outer `@m` and three anonymous inner arrays. ## Reading and writing elements `$m[1]` is the reference to the second row. To reach the third element of that row, apply the arrow: ```perl $m[1]->[2] # 6 $m[0]->[0] # 1 $m[2]->[2] = 99; # overwrite the bottom-right cell ``` Between **two subscripts**, the arrow is optional. This rule is what makes multidimensional access readable: ```perl $m[1][2] # same as $m[1]->[2] $m[2][2] = 99; # same as $m[2]->[2] = 99 ``` The arrow remains **required** between a scalar variable and its first subscript: `$aref->[0]` cannot be shortened to `$aref[0]` because that would mean "first element of `@aref`". The shortcut applies only **inside** a chain of subscripts. For three dimensions it's the same idea: ```perl $cube[2][3][5] # readable ${${$cube[2]}[3]}[5] # the same expression fully spelled out ``` The second form is what you'd have to write without the arrow shortcut. Nobody does that. ## Iterating over a matrix To walk rows, loop over the outer array; each iteration gives you an array reference. To walk cells, dereference that reference inside the loop: ```perl for my $row (@m) { for my $cell (@{$row}) { print "$cell "; } print "\n"; } ``` If you also need the indexes, use a counted loop on the outer array and on the dereferenced inner: ```perl for my $i (0 .. $#m) { for my $j (0 .. $#{$m[$i]}) { print "m[$i][$j] = $m[$i][$j]\n"; } } ``` `$#{$m[$i]}` is the last-index operator applied to the dereferenced inner array. It's the `$#array` form with `{$m[$i]}` standing in for the array name. ## Growing rows and columns Append to a row by pushing into the inner array via a reference: ```perl push @{$m[0]}, 10; # row 0 is now (1, 2, 3, 10) ``` Append a whole row to the matrix by pushing an array reference onto the outer array: ```perl push @m, [10, 11, 12]; # @m now has four rows ``` Both operations use [`push`](../../p5/core/perlfunc/push) — once on a dereferenced inner array, once on the outer array directly. ## Autovivification Assigning to `$m[$i][$j]` works even if `$m[$i]` doesn't exist yet: ```perl my @grid; $grid[5][7] = 'X'; ``` This creates `@grid` with six empty slots and one reference in slot 5. That reference points at a fresh anonymous array whose eighth slot holds `'X'`. Perl generates both the outer slot and the inner array automatically. This is called **autovivification** and is the reason you almost never have to write `$m[$i] = []` before using it. Autovivification fires on *assignment* and on *dereferencing in lvalue context*. Plain reads do **not** autovivify: ```perl my @grid; my $x = $grid[5][7]; # $x is undef; no inner array created exists $grid[5]; # false ``` Use [`defined`](../../p5/core/perlfunc/defined) to tell the "never existed" case from the "exists and holds `undef`" case, and [`exists`](../../p5/core/perlfunc/exists) to check the slot itself without autovivifying. ## Common mistake: sharing a single inner array This looks like three rows but is actually one row repeated: ```perl my @inner = (0, 0, 0); my @bad = (\@inner, \@inner, \@inner); $bad[0][1] = 9; print "$bad[2][1]\n"; # 9 — they're all the same array ``` To get three independent rows, construct each one separately. The anonymous-constructor form handles this by always allocating fresh: ```perl my @good = ([0, 0, 0], [0, 0, 0], [0, 0, 0]); $good[0][1] = 9; print "$good[2][1]\n"; # 0 ``` A loop over [`map`](../../p5/core/perlfunc/map) gives the same result for variable row lengths: ```perl my @grid = map { [ (0) x 10 ] } 1 .. 10; # 10×10 of zeros ``` ## Where to go next - *Hashes and mixes* — hashes of arrays and arrays of hashes, the two shapes that cover most real-world records. - *Anonymous references* — the `[...]` / `{...}` constructors used above, in detail.