Delete Element from Array
A common Perl programming question is “how can I remove one or more elements from an array?” Some approaches to this problem have unexpected side-effects best revealed by Data::Dumper and minimal test data.
#!/usr/bin/perl -w use strict; use Data::Dumper; my @a = qw(a b c);
The following methods may or may not work correctly:
shift off the unwanted element. Buggy, and illustrative why not reading the documentation for shift can get you in trouble.
for my $element ( @a ) { if ( $element eq 'b' ) { shift @a; } } print Dumper \@a;
Results in the first element of the array being removed, as specified in the documentation for shift. Yes, someone on #perl asked why this method did not work.
$VAR1 = [ 'b', 'c' ];
delete the unwanted element. This might be an obvious choice after pawing through perlfunc a bit.
for my $i ( 0 .. $#a ) { if ( $a[$i] eq 'b' ) { delete $a[$i]; } } print Dumper \@a;
This requires a slower C-style loop, and is also buggy! delete does not remove middle elements, instead replacing them with undef values. At best, this will result in Use of uninitialized value … errors. At worst, some horrible show stopping bug:
$VAR1 = [ 'a', undef, 'c' ];
splice the unwanted element. Also requires a slow C-style loop, and reveals a problem with modifying an array while looping over it:
for my $i ( 0 .. $#a ) { if ( $a[$i] eq 'b' ) { splice @a, $i, 1; } } print Dumper \@a;
Use of uninitialized value in string eq at test line 8. $VAR1 = [ 'a', 'c' ];
The element is correctly removed, though a warning is generated due to the array having shrunk so the former $#a value the for loop uses is now one beyond the current number in @a. And where there are warnings, be wary of bugs. For example, what happens when the array contains qw(a b b c)? The second b is not deleted, as it slides into the position of the first b after the splice, and is therefore missed by the next iteration!
Use grep and remove the unwanted element.
@a = grep { $_ ne 'b' } @a; print Dumper \@a;
Short, elegant, and supports the qw(a b b c) case that splice failed on. What I would use.
Other options would include building up a new array from things-that-are-not-b, or building up a list of element numbers to remove from the array, then splicing those (highest to lowest index!) from the original array. But why, when there’s grep?