Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Answer: How do I completely remove an element from an array?

by Minok (Novice)
on Apr 22, 2009 at 23:43 UTC ( #759438=categorized answer: print w/replies, xml ) Need Help??

Q&A > arrays > How do I completely remove an element from an array? - Answer contributed by Minok

I really liked the idea of using grep, as suggested:

@array = grep { $_ != $element_omitted } @array;
But then I got very concerned about the scope of things, particularly, when array is actually a reference to an array that has been passed into a subroutine and 'strict' is in use. I'm hoping that perl takes care of things, since we are indeed putting the temporary array created as part of the grep operation, back into the original array, which will stay in scope (and not be garbage collected when you leave a subroutine).

Replies are listed 'Best First'.
Re: Answer: How do I completely remove an element from an array?
by Minok (Novice) on Apr 23, 2009 at 00:05 UTC
    There is still the issue of fun things that happen when you edit an array that is used in the controlling loop (as others also pointed out above), so the grep solution gets fun with something like the following not working as one might think:

    foreach my $item ( (@array1, @array2) ) { if ( $item =~ /$pattern/i ) { @array1 = grep { $_ != $item } @array1; } }

    A solution I'll use to avoid all of the hard thinking is to just create a list of items to remove in the loop, and then as a separate operation delete them all:

    my @toRemove; foreach my $item ( (@array1, @array2) ) { if ( $item =~ /$pattern/i ) { push(@toRemove, $item); } } foreach my $item ( @toRemove ) { @array1 = grep { $_ ne $item } @array1; }
      my @toRemove; foreach my $item ( (@array1, @array2) ) { if ( $item =~ /$pattern/i ) { push(@toRemove, $item); } } foreach my $item ( @toRemove ) { @array1 = grep { $_ ne $item } @array1; }

      This is ugly, but to make this approach work, use a hash and remove a loop with a grep.

      my @toRemove = grep m/$pattern/i, @array1, @array2; my %toRemove = map { ($_ => 1) } @toRemove; @array1 = grep ! $toRemove{$_}, @array1;
      and if you like one liners, or simplicity, that becomes
      @array1 = grep ! m/$pattern/i, @array1;
      BTW: What is @array2 doing? It is useless unless you include it in the final line too.

      Now to your issue of fun things that happen when you edit an array that is used in the controlling loop: Yes, that can mess things up. That is part of the reason that you're better off avoiding loops when you're getting rid of data. List operators, like grep and map eliminate a lot of the need for explicit loops.

      Assigning a value to @array1 won't force change its scope. That will do the equivalent of empty all items from the list, and then push the new ones on to the end. No new variables will be created or destroyed.

      If you really like managing loops and arrays yourself, use for instead of foreach, keep an index, and use splice to remove stuff.

      splice @array,7,1;
      will remove the 7th element (remember to count from 0) from the array.

      Hope this helps

      -- doug

      Would it not be easier to undef the items to be removed, and then drop them from the array later ?

Re: Answer: How do I completely remove an element from an array?
by jdporter (Canon) on Apr 23, 2009 at 17:37 UTC

    The OP didn't saying anything about a "controlling loop" - that is something you have injected.

    In general, using splice to remove multiple elements from an array can be easily managed by starting at the end and working to the "left".

    for my $i ( reverse( 0 .. $#array ) ) { if ( $array[$i] =~ /criteria/ ) { splice @array, $i, 1; } }
    Between the mind which plans and the hands which build, there must be a mediator... and this mediator must be the heart.
Log In?
Username:
Password:

What's my password?
Create A New User
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2020-03-29 00:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    To "Disagree to disagree" means to:









    Results (168 votes). Check out past polls.

    Notices?