Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

How do I completely remove an element from an array?

by vroom (His Eminence)
on Jan 08, 2000 at 08:20 UTC ( [id://1871]=perlquestion: print w/replies, xml ) Need Help??

vroom has asked for the wisdom of the Perl Monks concerning the following question: (arrays)

How do I completely remove an element from an array?

Originally posted as a Categorized Question.

  • Comment on How do I completely remove an element from an array?

Replies are listed 'Best First'.
Re: How do I completely remove an element from an array?
by vroom (His Eminence) on Jan 09, 2000 at 10:16 UTC
    splice was designed to handle this.
    splice @array, $indextoremove, 1;

    splice can be called in any of the following forms:

    splice ARRAY, OFFSET, LENGTH #removes anything from the OFFSET index through the index OFFSET+LENGT +H-1 splice ARRAY, OFFSET, LENGTH, LIST #same as the previous but replaces elements removed with those in LIST splice ARRAY, OFFSET #removes anything from the OFFSET index on

    In any of these cases, splice returns the elements it removed.

Re: How do I completely remove an element from an array?
by jacques (Priest) on Sep 26, 2005 at 18:29 UTC
    I like using grep for this.

    @array = grep { $_ != $element_omitted } @array;
    (Be sure to use a test appropriate to the values in your array!)
Re: How do I completely remove an element from an array?
by jaa (Friar) on Mar 21, 2003 at 11:07 UTC

    Be careful using splice during array iteration.

    Note the subtle bug here:

    my @items = ( 0..5 ); my $index = 0; for my $value (@items) { print "testing $value\n"; if ( $value == 1 or $value == 3 ) { print "removed value $value\n"; splice @items, $index, 1; } $index++; }

    Values 2 and 4 are never actually tested for; iteration skips them completely!

    If you want to iterate over an array removing some items, try something like:

    my $index = 0; while ($index <= $#items ) { my $value = $items[$index]; print "testing $value\n"; if ( $value == 1 or $value == 3 ) { print "removed value $value\n"; splice @items, $index, 1; } else { $index++; } }

    And, this being Perl I bet there are many other safe iteration/splice approaches... 8-)

      You can also avoid the 'sliding' problem of skipping over elements because you removed the element before them by iterating backwards:

      for(reverse (0 .. $#items)) { splice(@items, $_, 1) if ($items[$_] == 1 || $items[$_] == 3); }

      Which is slightly obfuscated, but works because the sliding end of the array contains only the elements you have already checked...


      We're not surrounded, we're in a target-rich environment!
Re: How do I completely remove an element from an array?
by gridlock (Novice) on Feb 22, 2004 at 06:50 UTC
    You can use any of the following operators:
    pop()
    shift()
    splice()
    pop() and shift() will operate at the end and the beginning of an array respectively. splice() allows you to operate on an element somewhere in the middle..

    Originally posted as a Categorized Answer.

Re: How do I completely remove an element from an array?
by screamingeagle (Curate) on May 22, 2002 at 22:34 UTC
    how about :
    undef $array[$i]
    where $i is the element u wish to remove...

    This will not actually remove an element from the array, but will set the value to undef, which will mean that $array[$i] is not defined. scalar @array will still return the same number as before. Here's an example:

    my @array = qw( 1 2 3 4 ); print "there are ".scalar(@array)." elements in \@array \n"; print "the last index of \@array is $#array \n"; print "the 3'rd (index 2) value of \@array is $array[2] \n"; undef $array[2]; print "\$array[2] is now undefined \n" if not defined $array[2]; print "there are STILL ".scalar(@array)." elements in \@array \n"; print "the last index of \@array is STILL $#array \n";
Re: How do I completely remove an element from an array?
by dsb (Chaplain) on Jan 24, 2001 at 19:49 UTC
    Depends where the element is. If you know its on the left side of the array. You could use 'shift'. If its on the right, you could use 'pop'. But if you didn't know then you would want to use 'splice' in the way that the person above stated:
    splice( @array, offset, length );

    Originally posted as a Categorized Answer.

Re: How do I completely remove an element from an array?
by OzVegan (Acolyte) on Aug 28, 2009 at 03:16 UTC
    I'd iterate backwards through the array therefore avoiding the missing element syndrome when using an index counter. So if we were removing 1 and 3 from the following array...
    my @array = qw( alpha beta gamma delta ); for ( my $index = $#array; $index >= 0; --$index ) { splice @array, $index, 1 if $array[$index] =~ /e/; # remove certain elements }
Re: How do I completely remove an element from an array?
by Monkomatic (Sexton) on Oct 27, 2010 at 23:47 UTC
    You can use delete, as in:
    delete $ARRAY[$index];
    but note the warning:
    Calling delete on array values is deprecated and likely to be removed in a future version of Perl.
Re: How do I completely remove an element from an array?
by Minok (Novice) on Apr 22, 2009 at 23:43 UTC
    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).
      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 ?

      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.
Re: How do I completely remove an element from an array?
by deMize (Monk) on Aug 10, 2009 at 04:19 UTC
    I know this is old, but I stumbled across it and wanted to add that given the example, you could use the redo operator. Note incrementing the loop cursor ($value++) and then the redo;
    my @items = ( 0..5 ); my $index = 0; for my $value (@items) { print "testing $value\n"; if ( $value == 1 or $value == 3 ) { print "removed value $value\n"; splice @items, $index, 1; $value++; redo; } $index++; }

    Originally posted as a Categorized Answer.

Re: How do I completely remove an element from an array?
by St{) (Initiate) on Oct 19, 2002 at 06:59 UTC
    Well this is a little bit of a goose chase because you didn't quite give enough specifics and I am new to perl, but I think I know. It really depends what the element is and where it is. You can use "pop" and "shift" to my knowledge. I don't know what "splice" is quite yet. Anyway good luck! Oh, and if you want to know where to find out about "pop" and "shift" look at Learning Perl 3rd Edition near the end of chapter 3.

    -<STDIN>

      splice:

      splice ARRAY, OFFSET, LENGTH, LIST

      removes the elements designated by OFFSET and LENGTH and replaces them with the contents of LIST

      Also you'd be wise not to forget delete which deletes an element (or a slice of elements) from a specified hash or array.

      Bukowski - aka Dan (dcs@black.hole-in-the.net)
      "Coffee for the mind, Pizza for the body, Sushi for the soul" -Userfriendly

Re: How do I completely remove an element from an array?
by Astounded (Initiate) on Feb 17, 2014 at 18:10 UTC
    I'm no perl monk but I'll offer this as another way to do it:
    #!/usr/bin/perl use strict; # the original array elements my @a = ('1', '2', '3', '4', '5', '6', '7'); # the element we want to remove my $removeThis=3; # container for array elements my $arrayElement; # Temporarily Store the elements we want to keep here my @b; foreach $arrayElement (@a) { # it the element does not match the one we # want to remove we add it to the @b array: if ($arrayElement ne $removeThis) { push(@b, $arrayElement) } } # replace the elements in the @a array with those in # the @b array: @a=@b; # now print it out foreach $arrayElement(@a) {print $arrayElement} #result: #124567
    And I suppose if you want to turn it into a one liner this qualifies:
    for $i(@a){if($i ne $m){push(@b,$i)}} @a=@b;
    I honestly wouldn't know if there are any disadvantages to this approach. Perhaps others will comment on that.
      I would probably not declare $arrayElement in the broad scope, but instead use a lexical loop variable in each loop:
      for my $arrayElement (@a) { ... }

      The broad scope has no advantage, as the variable is localized anyway:

      If the variable is preceded with the keyword "my", then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with "my", it uses that variable instead of the global one, but it's still localized to the loop. This implicit localization occurs only in a "foreach" loop.

      (From perlsyn)

      لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: How do I completely remove an element from an array?
by Anonymous Monk on Mar 30, 2004 at 01:40 UTC
    You might use this in order to eliminate the duplicates from an array:
    my @items = qw ( 1 2 2 2 1 3 3 2 3 4 3 1 2 5 ); my $x, $y; $x = 0; foreach $a (@items) { $y = 0; foreach $b (@items) { if ($a == $b) { next; } if ($items[$x] == $items[$y]) { splice(@items, $y, 1); } $y++; } $x++; }

    Originally posted as a Categorized Answer.

Re: How do I completely remove an element from an array?
by jdporter (Paladin) on Feb 17, 2014 at 22:32 UTC

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

    Originally posted as a Categorized Answer.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1871]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-04-12 18:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found