Arrays

splice#

Remove and/or replace a slice of an array in place, and return the removed elements.

splice is the general-purpose array surgeon. Every other array mutator — push, pop, shift, unshift, single-element assignment — can be written as a splice call. Pick the position with OFFSET, pick how many elements to cut with LENGTH, and optionally supply a LIST of replacements. The array grows or shrinks to fit, and you get back whatever was cut out.

Synopsis#

splice @array;                              # remove everything
splice @array, $offset;                     # remove from $offset to the end
splice @array, $offset, $length;            # remove $length elements
splice @array, $offset, $length, @list;     # remove and replace with @list

What you get back#

  • List context: the list of elements that were removed, in their original order. Empty list if nothing was removed.

  • Scalar context: the last element removed, or undef if nothing was removed. This is rarely what you want — reach for list context unless you specifically need only the tail.

  • Void context: nothing; use this form when you only care about the in-place mutation.

Examples#

Basic removal — cut two elements starting at index 1:

my @a = ('a', 'b', 'c', 'd', 'e');
my @gone = splice @a, 1, 2;
# @a    == ('a', 'd', 'e')
# @gone == ('b', 'c')

Insert without removing — LENGTH is 0, so nothing comes out and the LIST is spliced in at OFFSET:

my @a = (1, 2, 5, 6);
splice @a, 2, 0, 3, 4;
# @a == (1, 2, 3, 4, 5, 6)

Replace a fragment — LENGTH and replacement size need not match. Here three elements leave, one arrives:

my @a = ('x', 'y', 'z', 'w', 'v');
my @gone = splice @a, 1, 3, 'Y';
# @a    == ('x', 'Y', 'v')
# @gone == ('y', 'z', 'w')

Remove the trailing tail — omit LENGTH entirely to cut from OFFSET to the end:

my @a = (1, 2, 3, 4, 5);
my @tail = splice @a, 3;
# @a    == (1, 2, 3)
# @tail == (4, 5)

Negative OFFSET counts from the end. Pop the last element:

my @a = ('a', 'b', 'c');
my $last = splice @a, -1;
# @a    == ('a', 'b')
# $last == 'c'

Classic idiom — consume an array $n elements at a time:

while (my @chunk = splice @queue, 0, $n) {
    process(@chunk);
}

All the common array primitives written as splice (assuming $#a >= $i):

push    @a, $x, $y;    #  splice @a, scalar(@a), 0, $x, $y
pop     @a;            #  splice @a, -1
shift   @a;            #  splice @a, 0, 1
unshift @a, $x, $y;    #  splice @a, 0, 0, $x, $y
$a[$i] = $y;           #  splice @a, $i, 1, $y

Edge cases#

  • Negative OFFSET counts from the end: -1 is the last element, -2 the one before, and so on. If the magnitude exceeds the array length, Perl issues a warning and clamps to 0.

  • Negative LENGTH leaves that many elements at the end of the array untouched. splice @a, 2, -1 removes from index 2 up to but not including the final element.

  • OFFSET past the end: with an explicit LENGTH, Perl issues a warning and splices at the end of the array (equivalent to splice @a, scalar(@a), 0, LIST). Without a LENGTH, nothing is removed.

  • LENGTH past the end: silently clamped. splice @a, 1, 999 simply removes everything from index 1 onward.

  • Both OFFSET and LENGTH omitted: removes every element. The array is left empty.

  • Replacement list size differs from LENGTH: the array grows or shrinks to match. There is no requirement that scalar(@list) equal LENGTH — that asymmetry is the whole point of splice.

  • Array reference: dereference inline. splice @$ref, 0, 1 and splice @{ $obj->{items} }, -2 both work.

  • Splicing a slice is not supported: splice @a[1..3], 0, 1 is a syntax error. splice requires a named array or dereferenced array, not a list expression. To operate on a range, pass the bounds as OFFSET and LENGTH instead.

  • Void context is fine. If the return value is not needed, call splice as a statement — no allocation of the removed-elements list happens in that case.

  • Scalar expressions as the first argument: not allowed. An experimental feature permitted this from 5.14 through 5.22 and was removed in 5.24. The first argument must be an array (or dereferenced arrayref).

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • push — append to the end; equivalent to splice @a, scalar(@a), 0, LIST

  • pop — remove the last element; equivalent to splice @a, -1

  • shift — remove the first element; equivalent to splice @a, 0, 1

  • unshift — prepend; equivalent to splice @a, 0, 0, LIST

  • delete — superficially similar but semantically different. delete $a[$i] leaves a hole (the slot becomes undef) and does not renumber later indices; the array’s length is unchanged unless the deleted slot was the last one. splice @a, $i, 1 physically removes the slot and shifts every later element down by one. Use delete for sparse arrays where index identity matters; use splice when you want the array to close up.

  • grep — filter an array into a new one by predicate; reach for it instead of splice when you want “keep only the ones that match” rather than “cut out a contiguous range”