Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

How do I get an array which is the logical AND of the elements of two other arrays?

by ibanix (Hermit)
on Feb 25, 2006 at 22:21 UTC ( #532810=perlquestion: print w/replies, xml ) Need Help??

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

After being away from perl coding for almost two years, I'm taking it up again. I have what feels like a rather trivial problem, but I'm not solving it very well.

I have two arrays, call them 'A' and 'B'. I need to produce an array 'C' which has only the elements present in both 'A' and 'B'. Furthermore, if an element IS found in both 'A' and 'B', I need to remove it from those arrays.

The end result is an array with elements from both starting arrays, and the two starting arrays with only the elements not present in both.

I can produce the joint list, but am not clear on how to weed the other two.

I tried something like this:
my @A = [ '1', '2', '4', '8' ]; my @B = [ '1', '3', '6', '8' ]; my @C; foreach my $A (@A) { foreach my $B (@B) { if ($A == $B) { push @C, $A; } // something here to take the elements out? } }
I also tried pop each value as I looped... with unhappy results.

Any help welcome, and thank you.
$ echo '$0 & $0 &' > foo; chmod a+x foo; foo;

Replies are listed 'Best First'.
Re: How do I get an array which is the logical AND of the elements of two other arrays?
by GrandFather (Saint) on Feb 25, 2006 at 22:58 UTC

    List::Compare may well be what you are looking for - reinventing wheels and all that.

    use warnings; use strict; use Data::Dump::Streamer; use List::Compare; my @A = ('1', '2', '4', '8'); my @B = ('1', '3', '6', '8'); my $lc = List::Compare->new (\@A, \@B); my @intersect = $lc->get_intersection; my @AOnly = $lc->get_Lonly; my @BOnly = $lc->get_Ronly; print "Intersection: @intersect\n"; print "A only: @AOnly\n"; print "B only: @BOnly\n";

    Prints:

    Intersection: 1 8 A only: 2 4 B only: 3 6

    DWIM is Perl's answer to Gödel
Re: How do I get an array which is the logical AND of the elements of two other arrays?
by ayrnieu (Beadle) on Feb 25, 2006 at 23:00 UTC
    my @C = List::Compare->new(qw/-u -a/, \@A, \@B)->get_intersection;

    Updated: and now that I actually read your code, I notice this problem:

    my @A = [ '1', '2', '4', '8' ]; my @B = [ '1', '3', '6', '8' ];

    The [...] you have here almost certainly isn't what you want. Try one of

    my @a = qw/1 2 4 8/; my $a = [qw/1 2 4 8/]; # an arrayref
      List::Compare was exactly what I wanted, thank you!
      $ echo '$0 & $0 &' > foo; chmod a+x foo; foo;
Re: How do I get an array which is the logical AND of the elements of two other arrays?
by InfiniteSilence (Curate) on Feb 25, 2006 at 23:35 UTC
    The Perl Cookbook covers examples like this, but here is a verbose solution if both arrays are of the same size:
    #!/usr/bin/perl -w use strict; my @a = qw|a b c d e|; my @b = qw|b c d c i|; my %a = map {$_=>1} @a; my %bank; for(0..$#b){ if(defined($a{$b[$_]})){ $bank{$b[$_]}++; $a{$b[$_]}++; undef $b[$_]; } } print "NEW \@A:\t" . join ',', sort grep { $a{$_}==1 } keys %a; print "\nNEW \@B:\t" . join ',', grep {defined($_)} @b; print "\nINCOMMON:\t" . join ',', keys %bank; 1; =========== C:\Temp>perl shoo.pl NEW @A: a,e NEW @B: i INCOMMON: c,b,d

    Celebrate Intellectual Diversity

Re: How do I get an array which is the logical AND of the elements of two other arrays?
by acid06 (Friar) on Feb 26, 2006 at 03:15 UTC
    Disclaimer: don't blame me for (ab)using weird idioms.
    This only maintains the ordering of the elements if your arrays were already sorted initially.
    my @A = (1,3,4,5,6,8); my @B = (1,3,5,7,9); my (%A, %B, @C); @A{@A} = (1) x @A; @B{@B} = (1) x @B; @C = grep { delete $B{$_} && delete $A{$_} } sort keys %A; @A = sort keys %A; @B = sort keys %B;

    acid06
    perl -e "print pack('h*', 16369646), scalar reverse $="
Re: How do I get an array which is the logical AND of the elements of two other arrays?
by spiritway (Vicar) on Feb 25, 2006 at 23:05 UTC

    Part of your problem seems to be that you want to modify the variables you're using in loops, which in my experience often has deplorable results. You might do better with skipping the part about taking the elements out, and do that once your @C array is created. Also note that your comment on line 13 begins with // instead of #, which could also give you unhappy results.

Re: How do I get an array which is the logical AND of the elements of two other arrays?
by EvanCarroll (Chaplain) on Feb 25, 2006 at 22:40 UTC
    You're probably not using the right tools, but given the circumstance and information I would either use Array::Unique or load them into a hash as keys and then read the keys of the hash.
    my %_; map { %_{$_} = undef } @arr1, @arr2; my @newarr = keys %_;
    Miss-read question, working this out again sry,
    What your going to want to do is splice the array, to delete the elements, but that solve the problem of duplicate elements in one array, ie.
    @a = (1,2,3,4,5); @b = (1,3,1,3,1);
    You want the second list to be empty? and the first list to have (2,4,5)?


    Evan Carroll
    www.EvanCarroll.com

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2022-08-18 01:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?