Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Compare two arrays

by Anonymous Monk
on Oct 01, 2014 at 16:10 UTC ( [id://1102555]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks!
I have two arrays, I need to find if the elements of the first array matchs any element on the second array. I am getting stuck once I have the account numbers into a hash:
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @account = qw( 96329XY 7776fc 334457yg 2233oop 000001 8877666b); my @file = qw(8877666b.txt 2233oop.txt 334457yg.txt 7776fc.txt 96329X +Y_K.txt); my %seen; for my $acc (@account) { next unless $acc =~ /^\d+/; my $key = $acc; push @{$seen{$key}}, $acc; } #print Dumper %seen; for my $filename (@file) { next unless $filename =~ /^\d+/; my $key = $filename; ... }

Thanks for looking!

Replies are listed 'Best First'.
Re: Compare two arrays
by Eily (Monsignor) on Oct 01, 2014 at 16:38 UTC

    You should uncomment print Dumper %seen; and write \%seen instead of %seen: you are probably not getting what you expect in your %seen hash.

    You may need to use captures in your regex (it depends on weither you want to use the whole name or just the number) in which case you'll find everything you need in Extracting matches (hint: it may be next unless $acc =~ /(^\d+)/; my $key = $1;/). Once your keys are what you expect them to be, in the filename loop you just have to check exists $seen{$key} to know if there is a match. See exists

      Why can't this work?
      ... for my $filename (@file) { next unless $filename =~ /^\d+/; if(grep { %seen{$_} =~ $filename} keys %seen) { print " $filename\n"; } else { print "$filename is not in array\n"; } }

        %seen{$_} is incorrect, you're only accessing one element (ie: a scalar) so you have to use the sigil $: $seen{$_}

        Now, look at your dump of \%test, you'll see that the value in $seen{$_} is actually an array, not a string, unless you have changed your data structure since the first post.

        Now your grep test (if I ignore your previous errors), applied to 96329XY and 96329XY_K.txt would turn into : "96329XY" =~ /96329XY_K.txt/, you probably have the wrong order. And you probably want to use quotemeta: grep { $filename =~ /\Q$_/ } keys %seen.

Re: Compare two arrays
by Bloodnok (Vicar) on Oct 01, 2014 at 17:43 UTC
    TIMTOWTDI ... why not try ...
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @account = qw( 96329XY 7776fc 334457yg 2233oop 000001 8877666b); my @file = qw(8877666b.txt 2233oop.txt 334457yg.txt 7776fc.txt 96329X +Y_K.txt); my $ac_re = join '|', grep /^\d+/, @account; print join "\n", grep /$ac_re/, @file;
    or similar ?

    Just a (nother) thought :-)

    A user level that continues to overstate my experience :-))
Re: Compare two arrays
by hippo (Bishop) on Oct 01, 2014 at 22:45 UTC
Re: Compare two arrays
by mr_mischief (Monsignor) on Oct 01, 2014 at 17:56 UTC

    Untested.

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @account = qw( 96329XY 7776fc 334457yg 2233oop 000001 8877666b); my @file = qw(8877666b.txt 2233oop.txt 334457yg.txt 7776fc.txt 96329X +Y_K.txt); my %seen; for my $acc (@account) { next unless $acc =~ /^\d+/; $seen{ $acc }++; # I'm not sure why you were pushing onto an array + to test for existence. } #print Dumper %seen; for my $filename (@file) { next unless $filename =~ /^(\d+.*?)\.txt$/; my $basename = $1; print "seen in account array: $basename\n" if exists $seen{ $basen +ame }; }
Re: Compare two arrays
by karlgoethebier (Abbot) on Oct 01, 2014 at 18:59 UTC

    I tried it using Set::Scalar:

    #!/usr/bin/env perl + use strict; use warnings; use Set::Scalar; my @account = qw( 96329XY 7776fc 334457yg 2233oop 000001 8877666b); my @file = qw(8877666b.txt 2233oop.txt 334457yg.txt 7776fc.txt 96329XY +_K.txt); s/\.txt// for @file; my $account_set = Set::Scalar->new(@account); my $file_set = Set::Scalar->new(@file); my $intersection = $account_set * $file_set; $intersection->as_string_callback( sub { join qq(\n), sort $_[0]->elem +ents } ); print qq($intersection\n); __END__ karls-mac-mini:monks karl$ ./1102555.pl + 2233oop + 334457yg + 7776fc + 8877666b

    Edit: Fixed wrong link to used module.

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

Re: Compare two arrays
by thanos1983 (Parson) on Oct 02, 2014 at 15:09 UTC

    Hello Anonymous Monk,

    I can see that everyone has all ready proposed answers and probably all of them are working. I just could not resist to the idea of trying also to create my own answer since I think it a useful topic comparing arrays.

    For my answer I use Data::Compare module which provides you which can provide you with several different outputs when you compare arrays. I have also combine my answer with a perlre (regular expression) taken from Regex To Remove File Extension which makes your solution more generic and not only to *.txt extensions.

    I would recommend to modify the title to something more appropriate (e.g. Comparing arrays with regex). This is because it produces confusion to people in future that are looking of simply comparing arrays without file extensions etc. etc.

    Having said that, sample of working code with output:

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; sub array_utils { use Array::Utils qw(:all); my @compare = (); my @account = qw( 96329XY 7776fc 334457yg 2233oop 000001 8877666b) +; my @file = qw(8877666b.txt 2233oop.txt 334457yg.txt 7776fc.txt 96 +329XY_K.txt); foreach my $sample (@file) { $sample =~ s/(.+)\.[^.]+$/$1/; push @compare,$sample; } # symmetric difference return my @diff = array_diff(@account, @compare); # intersection #return my @isect = intersect(@account, @compare); # unique union #return my @unique = unique(@account, @compare); # check if arrays contain same members if ( !array_diff(@account, @compare) ) { return "Arrays contain same members!"; } # get items from array @account that are not in array @compare #return my @minus = array_minus( @account , @compare ); } my @final = array_utils(); print Dumper(\@final); __END__ $VAR1 = [ '96329XY', '000001', '96329XY_K' ];

    Play around by removing the # symbols and observe the output, maybe one of them fits more to your needs.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (7)
As of 2024-04-23 14:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found