http://www.perlmonks.org?node_id=1010629

lovelyMonk has asked for the wisdom of the Perl Monks concerning the following question:

Hi I have two arrays : @arcb= (450,625,720,645); @arca=(625,645); I need to remove the elements of @arca from elements of @arcb so that the content of @arcb will be (450,720). Can anyone sugget me how to perform this operation?

Replies are listed 'Best First'.
Re: Removing elemets from an array
by linuxer (Curate) on Dec 28, 2012 at 08:18 UTC

    The hint to perlfaq4 is excellent.

    Use a hash and grep() and you are fine. No need for delete() or splice() here.

    #! /usr/bin/perl use strict; use warnings; my @arcb = ( 450, 625, 720, 645 ); my @arca = ( 625, 645 ); ### see perlfaq4 - How can I remove duplicate elements from a list or +array? my %unwanted; ### or %seen as in the faq4 $unwanted{$_}++ for @arca; @arcb = grep { !$unwanted{$_} } @arcb; print "@arcb\n"; + __END__

    Updates

      Worked perferctly for me :) Thankyou
Re: Removing elemets from an array
by davido (Cardinal) on Dec 28, 2012 at 10:17 UTC

    my @arcb = ( 450, 625, 720, 645 ); my @arca = ( 625, 645 ); @arcb = do { my %exclude; @exclude{@arca} = (); grep { ! exists $exclude{$_} } @arcb; }; print "@arcb\n";

    grep, and a narrowly scoped hash populated via a slice.


    Dave

Re: Removing elemets from an array
by Anonymous Monk on Dec 28, 2012 at 05:54 UTC

      Bit confusing with the reference,It is sure that the elements of @arca are in @arcb,but here am not having any indexes of those elements, but I need to remove them from the array @arcb.

Re: Removing elemets from an array
by nithins (Sexton) on Dec 28, 2012 at 06:38 UTC
    #!/usr/bin/perl use strict; my @arcb= (450,625,720,645); my @arca=(625,645); foreach my $a (@arca){ for(my $i=0;$i<scalar(@arcb);$i++){ delete $arcb[$i] if($a==$arcb[$i]); } } print "@arcb";

    hope this is what you were looking for....

      Thankyou,it worked for me, I heard that delete should be used only with hash,it might cause some problems when used with arrays. is it true?I can use this?
Re: Removing elemets from an array
by LanX (Saint) on Dec 28, 2012 at 13:07 UTC
    And for completeness, the hash slice approach:

    (Nota bene: repeated array elements will be deleted)

    DB<109> @arcb = ( 450, 625, 720, 645 ); => (450, 625, 720, 645) DB<110> @arca = ( 625, 645 ); => (625, 645) DB<111> @arcb{@arcb}=(); => (undef, undef, undef, undef) DB<112> @arca{@arca}=(); # EDIT: ehm ... sorry useless line... + => (undef, undef) DB<113> delete @arcb{@arca} => (undef, undef) DB<114> @arcb=keys %arcb => (450, 720)

    Cheers Rolf

Re: Removing elemets from an array
by karlgoethebier (Abbot) on Dec 28, 2012 at 16:51 UTC

      I hope you knoware aware, that your subroutines modify the data arrays globally?

      Take this example:

      #! /usr/bin/perl -l + use strict; + use warnings; + + our @array = ( 1 .. 5 ); + + sub foo { + our @array; + + print " inside before modification: @array"; + + # work with @array and modify it + @array = ( 'a' .. 'e' ); + + print " inside after modification: @array"; + } + + # now do the work + print "outside before calling foo(): @array"; + foo(); + print "outside after calling foo(): @array";

      This results in:

      outside before calling foo(): 1 2 3 4 5 inside before modification: 1 2 3 4 5 inside after modification: a b c d e outside after calling foo(): a b c d e

      As one can see, outside the sub, the array is changed as well.

      So afterTransferred to your benchmark script: With the first call of the first subroutine, the data arrays are modified. All following calls use that modified data and might change the data again. This might produce erroneous benchmark results.

      In the current setting, this might be not very severe. But there might be situations, where this is fatal!

      You should use separate arrays inside your sub routines (my @work = @array;), or localize the variables (local @array = @array;) inside the sub routines.

        "I hope you are aware, that your subroutines modify the data arrays globally?"

        Actually yes. Please don't ask why i did it this way ;-)

        Thanks, HNY and best regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

        Thanks for pointing this out. I knew I should have tested it since I rarely use 'our' and didn't really follow its use here. I just updated the code and redid the results of the tests.

      Update: Thanks to linuxer for pointing out that the original data were modified by the functions and therefore after the first call the other functions had a smaller data set. Here is the corrected version and the results.

      Updated again: realized I had warnings turned on and the nithins code warnings slowed down the benchmark a bunch when they printed to STDERR. Fixed the nithins approach.

      As I've seen BrowserUK do before I replaced the toy data set with something more realistic and the nithins approach became the slowest.

      I started with 10^6 and then 10^5 elements in the range but got warnings about too few iterations to make a comparison.

      #!/usr/bin/perl + use Benchmark qw ( :hireswallclock cmpthese timethese ); use strict; # use warnings; use Set::Scalar; use Data::Dumper; use List::Compare; # our @arcb = ( 450, 625, 720, 645 ); # our @arca = ( 625, 645 ); our @arcb = grep {$_ % 2} (1..10000); our @arca = grep {not $_ % 5} (1..10000); sub davido { #our @arcb; #our @arca; local @arcb = @arcb; local @arca = @arca; @arcb = do { my %exclude; @exclude{@arca} = (); grep { !exists $exclude{$_} } @arcb; }; # print "@arcb\n"; } sub karlgoethebier { #our @arcb; #our @arca; local @arcb = @arcb; local @arca = @arca; my $s1 = Set::Scalar->new(@arcb); my $s2 = Set::Scalar->new(@arca); @arcb = @{ $s1 - $s2 }; # print Dumper( \@arcb ); } sub Lotus1 { #our @arcb; #our @arca; local @arcb = @arcb; local @arca = @arca; my $lc = List::Compare->new( \@arca, \@arcb ); @arcb = $lc->get_Ronly; # print "arcb: @arcb\n"; } sub LanX { my ( %arcb, %arca ); #our @arcb; #our @arca; local @arcb = @arcb; local @arca = @arca; @arcb{@arcb} = (); # @arca{@arca} = (); update here delete @arcb{@arca}; @arcb = keys %arcb; # print Dumper( \@arcb ); } sub linuxer { #our @arcb; #our @arca; local @arcb = @arcb; local @arca = @arca; my %unwanted; $unwanted{$_}++ for @arca; @arcb = grep { !$unwanted{$_} } @arcb; # print "@arcb\n"; } sub nithins { #our @arcb; #our @arca; local @arcb = @arcb; local @arca = @arca; foreach my $a (@arca) { for ( my $i = 0 ; $i < scalar(@arcb) ; $i++ ) { #delete $arcb[$i] if ( $a == $arcb[$i] ); #fixed the warnings by using splice splice @arcb,$i,1 if ( $a == $arcb[$i] ); } } # print "@arcb"; } # karlgoethebier; # Lotus1; # LanX; # davido; # linuxer; # nithins; my $results = timethese( -20, { 'karlgoethebier' => 'karlgoethebier', 'Lotus1' => 'Lotus1', 'LanX' => 'LanX', 'davido' => 'davido', 'linuxer' => 'linuxer', 'nithins' => 'nithins', } ); cmpthese($results); __END__ Benchmark: running LanX, Lotus1, davido, karlgoethebier, linuxer, nith +ins for at least 20 CPU seconds... LanX: 21.5303 wallclock secs (21.14 usr + 0.38 sys = 21.52 CPU) + @ 143.25/s (n=3082) Lotus1: 20.4152 wallclock secs (20.27 usr + 0.14 sys = 20.41 CPU) + @ 24.55/s (n=501) davido: 20.1223 wallclock secs (19.72 usr + 0.38 sys = 20.09 CPU) + @ 110.78/s (n=2226) karlgoethebier: 22.1035 wallclock secs (22.06 usr + 0.03 sys = 22.09 +CPU) @ 22.22/s (n=491) linuxer: 21.5713 wallclock secs (21.14 usr + 0.42 sys = 21.56 CPU) + @ 147.39/s (n=3178) nithins: 21.1337 wallclock secs (21.09 usr + 0.00 sys = 21.09 CPU) + @ 0.66/s (n=14) Rate nithins karlgoethebier Lotus1 davido La +nX linuxer nithins 0.664/s -- -97% -97% -99% -10 +0% -100% karlgoethebier 22.2/s 3248% -- -9% -80% -8 +4% -85% Lotus1 24.6/s 3599% 10% -- -78% -8 +3% -83% davido 111/s 16590% 398% 351% -- -2 +3% -25% LanX 143/s 21482% 545% 483% 29% +-- -3% linuxer 147/s 22106% 563% 500% 33% +3% -- Note: the results below are the original version with the modified dat +a sets from the commented out 'our' array declarations. Benchmark: running LanX, Lotus1, davido, karlgoethebier, linuxer, nith +ins for at least 20 CPU seconds... LanX: 24.0026 wallclock secs (22.73 usr + 0.00 sys = 22.73 CPU) + @ 608.25/s (n=13828) Lotus1: 22.2431 wallclock secs (21.50 usr + 0.30 sys = 21.80 CPU) + @ 27.53/s (n=600) davido: 20.17 wallclock secs (19.81 usr + 0.33 sys = 20.14 CPU) @ + 199.25/s (n=4013) karlgoethebier: 20.2918 wallclock secs (19.95 usr + 0.33 sys = 20.28 +CPU) @ 14.35/s (n=291) linuxer: 20.1558 wallclock secs (19.87 usr + 0.26 sys = 20.14 CPU) + @ 321.91/s (n=6483) nithins: 20.9194 wallclock secs (20.89 usr + 0.00 sys = 20.89 CPU) + @ 0.77/s (n=16) Rate nithins karlgoethebier Lotus1 davido linuxe +r LanX nithins 0.766/s -- -95% -97% -100% -100 +% -100% karlgoethebier 14.3/s 1773% -- -48% -93% -96 +% -98% Lotus1 27.5/s 3494% 92% -- -86% -91 +% -95% davido 199/s 25915% 1289% 624% -- -38 +% -67% linuxer 322/s 41932% 2144% 1069% 62% - +- -47% LanX 608/s 79319% 4139% 2110% 205% 89 +% --

      updated with LanX's update

        This is very interesting. But for the moment i don't have any idea why it is so.

        Perhaps some of the involved brothers would like to comment/interprete the result so we can learn something new?

        Best regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

Re: Removing elemets from an array
by Lotus1 (Vicar) on Dec 28, 2012 at 16:43 UTC
    #!/usr/bin/perl use warnings; use strict; use List::Compare; my @arca = qw( 625 645 ); my @arcb = qw( 450 625 720 645 ); print "arcb: @arcb\n"; my $lc = List::Compare->new( \@arca, \@arcb); # get the items which appear only in the second list. @arcb = $lc->get_Ronly; print "arcb: @arcb\n";