Re: How can I delete an element in a foreach cycle?
by kennethk (Abbot) on Feb 26, 2010 at 23:12 UTC
|
Is there a particular need to do this in a foreach loop and in place? For example, this would seem to me to be a textbook example of when to use grep:
@array = qw(hi hello howdy);
@array = grep {!/^hello$/} @array;
print join "\n", @array;
If you need to do this in the context of a loop, perhaps it would make sense to combine loop control with undef and filtering after the loop:
@array = qw(hi hello howdy);
for (@array) {
if ($_ eq 'hello') {
undef $_;
next;
}
# Process list elements
}
@array = grep {defined} @array;
print join "\n", @array;
| [reply] [d/l] [select] |
|
That would filter out any elements that were undefined to begin with. Another solution:
my @keep;
for (my $i = 0; $i < @array; $i++) {
my $_ = $array[$i];
push @keep, $i unless $_ eq 'hello';
}
@array = @array[@keep];
Or:
for (my $i = @array; $i--;) {
splice @array, $i, 1 if $array[$i] eq 'hello';
}
But splice can be expensive; don't use that when deleting lots of things from a huge array. | [reply] [d/l] [select] |
|
It's never a good idea to mess with the JavaFan, but would either of those approaches be faster or more straightforward than, or in any way preferable to something like (assuming the array may contain undefined elements):
>perl -wMstrict -le
"my @array = (qw(hi hiya hello hello), undef, qw(lo hello));
@array = grep !defined || $_ ne 'hello', @array;
print defined($_) ? qq{'$_'} : 'UNDEF' for @array;
"
'hi'
'hiya'
UNDEF
'lo'
| [reply] [d/l] |
|
|
|
|
|
|
|
|
Re: How can I delete an element in a foreach cycle?
by CountZero (Bishop) on Feb 27, 2010 at 08:49 UTC
|
Generally it is considered a bad idea to delete or add elements to an array your are looping over. Unless you are very careful, you might either skip elements or fall into an infinite loop.That being said, if you do not mind adding a temporary variable, this is another solution: use strict;
use warnings;
my @array = qw /aap noot mies wim zus jet teun vuur gijs lam kees bok
+weide does hok duif schapen/;
my @temp_array;
for (@array) {
push @temp_array, $_ unless /a/;
}
@array = @temp_array;
{ local $, = '|'; print @array; }
Or at the cost cost of some added complexity, using slices and grep and map (how perlish can you get?):
use strict;
use warnings;
my @array = qw /aap noot mies wim zus jet teun vuur gijs lam kees bok
+weide does hok duif schapen/;
my $counter = -1;
@array = @array[grep {$_} map {$counter++; /a/ ? undef : $counter;} @a
+rray];
{ local $, = '|'; print @array; }
the output of both is:noot|mies|wim|zus|jet|teun|vuur|gijs|kees|bok|weide|does|hok|duif
Update: added another solution.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] [d/l] [select] |
Re: How can I delete an element in a foreach cycle?
by shmem (Chancellor) on Feb 27, 2010 at 10:55 UTC
|
TIMTOWTDI. You could remember the indices and splice the goners out, highest first:
my @goners;
for (0 .. $#ARGV) {
unshift @goners, $_ if $ARGV[$_] eq 'hello';
}
splice @ARGV, $_, 1 for @goners;
update: $#ARGV instead of @ARGV-1 as per dsheroh's comment below. | [reply] [d/l] [select] |
|
Any particular reason for @ARGV-1 instead of $#ARGV?
| [reply] [d/l] [select] |
|
Other than TIMTOWTDi, no ;-) But $#ARGV is better, since it needn't be calculated. - corrected, thanks.
| [reply] [d/l] |
|
|
for my $i ( reverse 0 .. $#ARGV ) {
splice( @ARGV, $i, 1 ) if $ARGV[$i] eq 'hello';
}
| [reply] [d/l] |
Re: How can I delete an element in a foreach cycle?
by repellent (Priest) on Mar 01, 2010 at 03:55 UTC
|
my @array = qw(hi hello howdy);
my @hellos = grep_and_remove { $_ eq 'hello' } @array;
use Data::Dumper;
print Dumper \@array;
__END__
$VAR1 = [
'hi',
'howdy'
];
| [reply] [d/l] [select] |