Perl intermediate

How to Add Elements to an Array in Perl (push, unshift, splice, indexing, and arrayrefs)

Question

how to add elements to an array perl

Difficulty: Beginner → Intermediate

Tags: perl, arrays, push, unshift, splice, indexing, arrayref, best-practices

Overview

In Perl, an array is an ordered list of scalar values. Arrays are one of Perl’s core data types and are extremely flexible: you can grow them, shrink them, insert into the middle, prepend to the front, and even assign to specific indexes far beyond the current length (creating “holes”).

The most common ways to add elements to an array are:

  • Append to the end with push
  • Prepend to the beginning with unshift
  • Insert (or replace) anywhere with splice
  • Assign by index (including extending the array)
  • Concatenate lists by building a new array (useful, but less efficient in loops)
  • Work with array references using push @{ $aref }, ...

Perl array basics (quick refresher)

In Perl, @array refers to the entire array in list context. Individual elements are scalars and are accessed with $array[index]. This is a common source of confusion for beginners:

  • @names is the whole array (list)
  • $names[0] is the first element (scalar)

Most array-growing operations happen in-place (they modify the array directly), which is usually what you want.

1) Add elements to the end: push

push appends one or more elements to the end of an array:

  • push @a, $x; appends one element
  • push @a, $x, $y, $z; appends multiple elements
  • push @a, @b; appends all elements of @b (flattened)

Important: push returns the new length of the array, not the array itself.

Runnable example 1 (push + unshift + splice)

use strict;
use warnings;

my @a = (1, 2);

push @a, 3;          # add to end
unshift @a, 0;       # add to beginning
splice @a, 2, 0, 1.5;# insert at index 2, delete 0, insert 1.5

print join(",", @a), "\n";

Expected output:

0,1,1.5,2,3

2) Add elements to the beginning: unshift

unshift prepends one or more elements to the front of the array. Existing elements move to higher indexes to make room:

  • unshift @a, $x; prepends one element
  • unshift @a, $x, $y; prepends multiple elements

Performance note: Because every existing element must be moved, repeated unshift operations on very large arrays can be slower than push. If you need stack-like behavior, use push/pop. For queue-like behavior, push/shift is common, but for very large queues you might consider a different structure (or modules) if performance becomes an issue.

3) Insert (or replace) anywhere: splice

splice is the most powerful array-editing tool. It can:

  • Insert into the middle
  • Delete a range
  • Replace a range with new elements

The common form is:

splice @array, $offset, $length, @replacement;
  • $offset: where to start (0-based). Negative offsets count from the end.
  • $length: how many elements to remove
  • @replacement: optional list to insert in place of removed elements

To insert without deleting, set $length to 0 (as in Example 1).

Common pitfall: splice returns the removed elements. If you accidentally assign it back, you may overwrite your data:

# Wrong if you meant to modify @a in-place:
@a = splice(@a, 2, 0, "x");  # @a becomes the removed items (often empty!)

The correct in-place usage is typically just:

splice @a, 2, 0, "x";

4) Add/extend by assigning to an index

You can assign directly to an index to set or add an element:

my @a;
$a[0] = "first";   # adds at index 0
$a[3] = "fourth";  # extends array, indexes 1 and 2 become undef

If you assign to an index beyond the current end, Perl extends the array and fills the gap with undef values. Those “holes” can surprise you later when you iterate or join the array.

Runnable example 2 (index assignment + appending multiple items)

use strict;
use warnings;

my @colors;

$colors[2] = "blue";   # array auto-extends
$colors[0] = "red";
$colors[1] = "green";

print join(" ", @colors), "\n";

push @colors, qw(yellow purple);
print scalar(@colors), "\n";

Expected output:

red green blue
5

Because we set indexes 0, 1, and 2, there are no holes. If we had only set $colors[2] and printed immediately, the first two elements would have been undef (which can print as empty strings under join).

5) Add multiple elements by list concatenation (useful, but be careful in loops)

You can create a new array containing old and new elements using list construction:

@a = (@a, $new_value);          # append one
@a = ($new_value, @a);          # prepend one
@a = (@a, @more_values);        # append many

This is perfectly valid and sometimes reads nicely in small scripts. However, it generally creates a new list and can be less efficient than push/unshift, especially inside large loops.

Best practice: prefer push for repeated appends and unshift for occasional prepends; reserve list concatenation for one-off transformations or when you specifically want to create a new array value (for example, when you do not want to mutate the original).

6) Adding elements to array references (arrayrefs)

In real programs, you often work with array references (especially in data structures or when passing arrays to subroutines without copying). If $aref is an array reference, you add elements like this:

  • push @{ $aref }, $x;
  • unshift @{ $aref }, $x;
  • splice @{ $aref }, $offset, $len, @repl;

Runnable example 3 (arrayref push/unshift)

use strict;
use warnings;

my $aref = [];

push @$aref, "alpha";
push @$aref, qw(beta gamma);
unshift @$aref, "start";

print join("->", @$aref), "\n";

Expected output:

start->alpha->beta->gamma

Notice the shorthand: push @$aref, ... is equivalent to push @{ $aref }, .... Both are common; the shorter form is idiomatic when it stays readable.

Best practices

  • Use use strict; use warnings; in scripts and modules. It catches many common mistakes early, especially typos and accidental global variables.
  • Prefer push for building lists (especially in loops). It is idiomatic and avoids repeated list copying.
  • Be explicit about what you’re pushing: push @a, @b; flattens @b. If you intended to push a reference to @b as a single element, do push @a, \@b;.
  • Watch out for holes when assigning to far indexes (they become undef). If you need a dense list, build it with push or ensure all intermediate values are set.
  • Use splice sparingly and clearly. It’s powerful but easier to get wrong. Consider extracting intent into helper subs if the offsets/lengths are complex.
  • Don’t confuse return values: push/unshift return the new length; splice returns removed elements.

Common pitfalls (and how to avoid them)

  • Accidentally overwriting your array with push’s return value:
    my @a;
    @a = push @a, 1;   # WRONG: @a becomes (1) because push returns new length
    
    Correct usage is just push @a, 1; (no assignment), or capture the length in a scalar: my $len = push @a, 1;.
  • Forgetting the sigil difference: @a vs $a[0]. Remember: element access uses $ because it’s a scalar.
  • Joining arrays with undef holes: holes turn into empty strings under join and can hide bugs. If you suspect holes, check with something like:
    for my $i (0..$#a) {
      print "$i: ", (defined $a[$i] ? $a[$i] : "(undef)"), "\n";
    }
    
  • Pushing an array reference when you meant to flatten (or vice versa). Know whether you want one element (a reference) or many (a list).
  • Using list concatenation in a hot loop: @a = (@a, $x) repeatedly can be noticeably slower than push @a, $x for large data sets.

Real-world usage patterns

Pattern A: Build a list from input

When reading lines from a filehandle and collecting them, push is the standard tool:

my @lines;
while (my $line = <STDIN>) {
  chomp $line;
  push @lines, $line;
}

This produces a clean, dense list in the order read.

Pattern B: Insert markers or headers

If you need to add a header before a list of rows (for example, a CSV header), unshift is direct:

unshift @rows, "id,name,email";

Pattern C: Maintain a small rolling window

A common approach is to push new items and shift old ones to keep only the last N values:

push @window, $value;
shift @window while @window > 100;

This is simple and effective for moderate sizes; if N is huge and performance matters, you might consider alternative structures, but for many applications it’s plenty.

Summary

To add elements to a Perl array, the idiomatic choices are push (append) and unshift (prepend). For inserting or replacing elements at arbitrary positions, use splice. You can also extend arrays by direct index assignment, but be aware it can create undef holes. In real programs, you’ll often do the same operations on array references using push @$aref, .... Stick with use strict and use warnings, understand the return values of these functions, and you’ll avoid most common array-growth bugs.

Verified Code

Executed in a sandbox to capture real output. • 5ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
0,1,1.5,2,3
STDERR
(empty)

Was this helpful?

Related Questions