# Arrays An array is an ordered, integer-indexed sequence of scalars. The sigil is `@` for the whole array and for slices (which are lists); `$` for a single element (which is one scalar). The leading sigil tells you the *result type*, not the container. ```perl my @days = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri'); @days # the whole array (5 elements) $days[0] # the first element — a single scalar @days[1, 3] # a slice — a list of two scalars $#days # the last valid index — here, 4 scalar @days # the length — here, 5 ``` Indices start at 0. Negative indices count from the end (`$days[-1]` is `'Fri'`). ## Length: `$#arr` vs `scalar @arr` Two related quantities, used for different jobs: ```perl $#days # last valid index — 4 scalar @days # number of elements — 5 $#days + 1 # equivalent to scalar @days ``` Assigning to `$#arr` resizes the array. Shrinking destroys the elements past the new end; growing fills them with `undef`: ```perl my @a = (1, 2, 3, 4, 5); $#a = 2; # @a is now (1, 2, 3) — length 3 $#a = 5; # @a is now (1, 2, 3, undef, undef, undef) $#a = -1; # @a is now () — empty ``` The `@a = ()` form is the idiomatic empty-array assignment; `$#a = -1` is equivalent and occasionally clearer when the intent is ”shrink to nothing without changing the variable’s identity“. ## Element access ```perl my $first = $days[0]; # 'Mon' my $last = $days[-1]; # 'Fri' my $last = $days[$#days]; # same; redundant but explicit $days[2] = 'Wednesday'; # set $days[10] = 'Sunday'; # auto-extends; $days[5..9] become undef ``` Reading past the end returns `undef` (no warning — out-of-range read is a non-event). Writing past the end *grows* the array; the intervening slots become `undef`. ```perl my @a; $a[5] = 'fifth'; # @a is now (undef, undef, undef, undef, undef, 'fifth') print scalar @a; # 6 ``` Reading a negative index further back than the start is a *fatal* error: ```perl my @a = (1, 2, 3); $a[-10]; # FATAL: Modification of non-creatable # array value attempted ``` ## The whole-array operations ```perl push @arr, $value; # append at end — returns new length my $v = pop @arr; # remove from end — returns removed element my $v = shift @arr; # remove from start — returns removed element unshift @arr, $value; # prepend — returns new length splice @arr, $offset, $len, @replacement; # general remove/insert ``` `shift` and `unshift` are O(n) because they renumber every remaining element; `push` and `pop` are O(1) amortised. For queue-shaped workloads where this matters, prefer `push`/`shift` on the *short* end or use a deque from [`List::Util`](../../List/Util.md) (which has reductions, not a deque). `splice` is the swiss-army knife: remove a stretch of elements, insert a stretch in their place, return what was removed: ```perl my @arr = (1, 2, 3, 4, 5); my @gone = splice @arr, 1, 2; # @gone = (2, 3); @arr = (1, 4, 5) splice @arr, 1, 0, ('a', 'b'); # insert at offset 1, no removal # @arr = (1, 'a', 'b', 4, 5) ``` A negative `$offset` counts from the end. A negative `$len` keeps that many trailing elements: ```perl splice @arr, -1; # remove just the last element splice @arr, 0, -2; # remove all but the last two ``` ## Slices A slice extracts (or assigns to) several elements at once. Indices come from a list: ```perl my @arr = ('a', 'b', 'c', 'd', 'e'); my @subset = @arr[0, 2, 4]; # ('a', 'c', 'e') my @middle = @arr[1..3]; # ('b', 'c', 'd') my @last3 = @arr[-3..-1]; # ('c', 'd', 'e') my @rev = @arr[reverse 0..$#arr]; # ('e', 'd', 'c', 'b', 'a') @arr[1, 3] = ('B', 'D'); # set positions 1 and 3 @arr[1, 3] = @arr[3, 1]; # swap two elements (no temp) ``` A *key/value* slice with `%` returns index/value pairs (Perl 5.20+): ```perl my @arr = ('a', 'b', 'c', 'd', 'e'); my %picked = %arr[1, 3]; # (1 => 'b', 3 => 'd') ``` This is the right shape when you need both the index and the value of selected elements. See [subscript](../perlop/subscript.md) for the twelve-way matrix of slice forms. ## List context vs scalar context An array in list context yields its elements; in scalar context, it yields its length: ```perl my @arr = (10, 20, 30); my @copy = @arr; # list context — three elements my $length = @arr; # scalar context — 3 print "got @arr\n"; # list context inside "" — "got 10 20 30" print "got " . @arr . "\n"; # scalar context (concat) — "got 3" ``` The distinction is the most common Perl trap. Two rules of thumb: - *Inside double-quoted strings*, arrays interpolate as their elements joined by `$"` (a single space by default). See [interpolation](interpolation.md). - *In a numeric or string operator context* (`+`, `.`, comparison), an array yields its length. Force scalar context with [`scalar`](../perlfunc/scalar.md) when the expression position is otherwise ambiguous: ```perl print "got " . scalar(@arr) . " items\n"; # "got 3 items" print "got @arr items\n"; # "got 10 20 30 items" — different! ``` ## List assignment and the count idiom Assigning a list to an array makes the array exactly that long: ```perl my @arr = (1, 2, 3); @arr = (10, 20); # @arr is now (10, 20) @arr = (); # @arr is now empty ``` Assigning a list to a *list* of scalars unpacks (any extras are discarded; missing ones become `undef`): ```perl my ($x, $y, $z) = (1, 2, 3); # 1, 2, 3 my ($x, $y, $z) = (1, 2); # 1, 2, undef my ($x, $y) = (1, 2, 3); # 1, 2 — '3' silently dropped ``` A list assignment in scalar context returns the number of elements on the *right* side. This is the source of the count idiom: ```perl my $count = () = $string =~ /\d+/g; # $string =~ /\d+/g — match in list context, returns all matches # () = LIST — list assignment to empty list # $count = SCALAR — that assignment in scalar context = count of RHS ``` The `() = LIST` middle is the trick. Without it, `$count = $s =~ /\d+/g` gives a boolean instead of a count. ## Array references Arrays are not first-class values in the sense that they can be passed by name through a chain of function calls without flattening into a list. To pass an array around without flattening, take a **reference** to it: ```perl my @items = (1, 2, 3); my $aref = \@items; # reference to the existing @items my $anon = [1, 2, 3]; # anonymous array reference $aref->[0] # access through the arrow — 1 @{$aref} # fully bracketed deref — list (1, 2, 3) @$aref # unbracketed deref — same as above $#{$aref} # last index of dereffed array scalar @$aref # length ``` See [references](references.md) for the full picture. ## Real example: building a histogram of word lengths ```perl my @words = qw(the quick brown fox jumps over the lazy dog); my @hist; $hist[length $_]++ for @words; for my $len (1 .. $#hist) { next unless $hist[$len]; printf "%2d-letter words: %d\n", $len, $hist[$len]; } # 3-letter words: 4 # 4-letter words: 2 # 5-letter words: 3 ``` Note `$hist[length $_]++` autovivifies (creates) the slot when it’s the first word of that length. Reading from `$hist[7]` later returns `undef`, which `++` happily increments — but `next unless $hist[$len]` skips the gap before printing. ## See also - [Hashes](hashes.md) — when the index is a string, not an integer. - [References](references.md) — passing arrays around without flattening. - [Context](context.md) — the list-vs-scalar story expanded. - [Interpolation](interpolation.md) — how arrays appear inside `""`. - [Subscript and slice operators](../perlop/subscript.md) — the bracket-and-brace family in detail. - [Range operator `..`](../perlop/range.md) — the most common source of slice index lists. - [`push`](../perlfunc/push.md), [`pop`](../perlfunc/pop.md), [`shift`](../perlfunc/shift.md), [`unshift`](../perlfunc/unshift.md), [`splice`](../perlfunc/splice.md) — the whole-array operations. - [`scalar`](../perlfunc/scalar.md) — force scalar context (length). - [`reverse`](../perlfunc/reverse.md), [`sort`](../perlfunc/sort.md) — whole-array transformations.