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

is there a more simple way to have the intersection of two lists ?

by steph_bow (Pilgrim)
on Mar 18, 2008 at 13:41 UTC ( [id://674782]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks,

Is there another way to have the intersection of two lists ? Thanks a lot

Here is my code

#usr/bin/perl use strict; my $name_1 = q{list_1.txt}; my $name_2 = q{list_2.txt}; open my $INFILE_1, q{<}, $name_1 or die "Can't open $name_1 : $!"; open my $INFILE_2, q{<}, $name_2 or die "Can't open $name_2 : $!"; my @list_1; while (my $line_1 = <$INFILE_1>){ $line_1 =~ s/\s+$//; push @list_1, $line_1; } my @list_2; while (my $line_2 = <$INFILE_2>){ $line_2 =~ s/\s+$//; push @list_2, $line_2; } my @intersection; my %count; my $element; my @two_lists = (@list_1,@list_2); print STDOUT "@two_lists\n"; foreach $element(@two_lists){ $count{$element}++; } my $key; my @KEYS = keys %count; foreach $key(@KEYS){ if ($count{$key} == 1){ print STDOUT "$key;$count{$key}\n\n"; } } close $INFILE_1; close $INFILE_2;
Here is the first file
car train plane
Here is the second file
boat car train

Replies are listed 'Best First'.
Re: is there a more simple way to have the intersection of two lists ?
by poolpi (Hermit) on Mar 18, 2008 at 13:58 UTC
    See List::Compare
    $lc = List::Compare->new(\@Llist, \@Rlist); @intersection = $lc->get_intersection;
    hth

    PooLpi
    'Ebry haffa hoe hab im tik a bush'. Jamaican proverb
Re: is there a more simple way to have the intersection of two lists ?
by dragonchild (Archbishop) on Mar 18, 2008 at 13:58 UTC
    Use CPAN instead.
    use Set::Scalar; my @filenames = ( 'name1.txt', 'name2.txt' ); my @sets = map { read_file_to_set( $_ ) } @filenames; my $intersection = $sets[0]->intersection( $sets[1] ); print "$intersection\n"; sub read_file_to_set { my ($filename) = @_; open my $fh, '<', $filename or die "Cannot open '$filename' for reading: $!\n"; chomp( my @lines = <$fh> ); close $fh; return Set::Scalar->new( @lines ); }

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: is there a more simple way to have the intersection of two lists ?
by alexm (Chaplain) on Mar 18, 2008 at 14:05 UTC
Re: is there a more simple way to have the intersection of two lists ?
by zby (Vicar) on Mar 18, 2008 at 13:57 UTC
    I use Set::Scalar and it really fits the way I think (my mathematical background taught me treat set operations as the basic 'atomic' functions). There is also Set::Bag if your lists are really multi-sets (i.e. can contain the same element multiple times).
Re: is there a more simple way to have the intersection of two lists ?
by moritz (Cardinal) on Mar 18, 2008 at 13:59 UTC
    You don't have to write all that lines into an array:
    my %count; while (my $line_1 = <$INFILE_1>){ $line_1 =~ s/\s+$//; $count{$line_1}++; } while (my $line_2 = <$INFILE_2>){ $line_2 =~ s/\s+$//; print $line_2, "\n" if $count{$line_2}; } # untested
Re: is there a more simple way to have the intersection of two lists ?
by ikegami (Patriarch) on Mar 18, 2008 at 14:39 UTC
    If neither list contains duplicate elements:
    my %seen; my @intersection = grep ++$seen{$_}==2, @list1, @list2;
    Or if they could
    my %seen; $seen{$_}=1 for @list1; my @intersection = grep ++$seen{$_}==2, @list2;

    Update: $seen{}$seen{$_}

      my %seen; $seen{$_}=1 for @list1; my @intersection = grep ++$seen{}==2, @list2;
      You are missing a $_ there. And it doesn't work. (Consider @list1=(); @list2=qw(foo foo);.)

        Hum, right. I over-optimized. I should have stuck to the general solution (i.e. accepts more than two sets) I first wrote.

        my %seen; $seen{$_}|=1<<0 for @list1; $seen{$_}|=1<<1 for @list2; my @intersection = grep $seen{$_}==(1<<2)-1, keys %seen;

        It loses any order, though.

Re: is there a more simple way to have the intersection of two lists ?
by kyle (Abbot) on Mar 18, 2008 at 14:50 UTC

    If you read the first list into a hash instead of an array, you can then use a hash slice with the second array to get the intersection.

    #usr/bin/perl use strict; my $name_1 = q{list_1.txt}; my $name_2 = q{list_2.txt}; open my $INFILE_1, q{<}, $name_1 or die "Can't open $name_1 : $!"; open my $INFILE_2, q{<}, $name_2 or die "Can't open $name_2 : $!"; my %list_1; # changed while (my $line_1 = <$INFILE_1>){ $line_1 =~ s/\s+$//; $list_1{$line_1} = $line_1; # changed } my @list_2; while (my $line_2 = <$INFILE_2>){ $line_2 =~ s/\s+$//; push @list_2, $line_2; } close $INFILE_1; close $INFILE_2; # changed from here down my @intersection = grep { defined } @list_1{@list_2}; foreach my $line ( @intersection ) { print "$line\n"; }

    This also requires that list 2 not have duplicate elements.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2024-04-25 17:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found