How to compare arrays in Perl?

I have two arrays, @a and @b . I want to make a comparison between the elements of two arrays.

 my @a = qw"abc def efg ghy klm ghn"; my @b = qw"def ghy jgk lom com klm"; 

If any item matches, set the flag. Is there an easy way to do this?

+7
arrays perl
source share
12 answers

First of all, your 2 arrays must be written correctly.

 @a = ("abc","def","efg","ghy","klm","ghn"); @b = ("def","efg","ghy","klm","ghn","klm"); 

Secondly, for arbitrary arrays (for example, arrays whose elements can be references to other data structures), you can use Data::Compare .

For arrays whose elements are scalar, you can perform a comparison using List::MoreUtils pairwise BLOCK ARRAY1 ARRAY2 , where BLOCK is your comparison routine. You can emulate pairwise (if you do not have access to the :: MoreUtils list) with:

 if (@a != @b) { $equals = 0; } else { $equals = 1; foreach (my $i = 0; $i < @a; $i++) { # Ideally, check for undef/value comparison here as well if ($a[$i] != $b[$i]) { # use "ne" if elements are strings, not numbers # Or you can use generic sub comparing 2 values $equals = 0; last; } } } 

PS I'm not sure, but List :: Compare can always sort lists. I'm not sure that he can do pairwise comparisons.

+9
source share

List :: Compare

 if ( scalar List::Compare->new(\@a, \@b)->get_intersection ) { … } 
+7
source share

Check to create an intersection function that returns a list of elements that are in both lists. Then your return value depends on the number of items in the crosslist.

You can easily find the best intersect implementation for Perl on the Internet. I remember looking for him a few years ago.

Here is what I found:

 my @ array1 = (1, 2, 3);
 my @ array2 = (2, 3, 4);
 my% original = ();
 my @isect = ();

 map {$ original {$ _} = 1} @ array1;
 @isect = grep {$ original {$ _}} @ array2;

+4
source share

This is one way:

 use warnings; use strict; my @a = split /,/, "abc,def,efg,ghy,klm,ghn"; my @b = split /,/, "def,ghy,jgk,lom,com,klm"; my $flag = 0; my %a; @a{@a} = (1) x @a; for (@b) { if ($a{$_}) { $flag = 1; last; } } print "$flag\n"; 
+2
source share
 my @a = qw' abc def efg ghy klm ghn '; my @b = qw' def ghy jgk lom com klm '; my $flag; foreach my $item(@a) { $flag = @b~~$item ? 0 : 1; last if !$flag; } 

Note that you will need Perl 5.10 or later to use the smart matching operator ( ~~ ).

+1
source share

From the requirement that "if any element matches", use the intersection of sets:

 sub set{ my %set = map { $_, undef }, @_; return sort keys %set; } sub compare{ my ($listA,$listB) = @_; return ( (set(@$listA)-set(@$listB)) > 0) } 
+1
source share

Brute force should do the trick for small a n :

 my $flag = 0; foreach my $i (@a) { foreach my $k (@b) { if ($i eq $k) { $flag = 1; last; } } } 

For large n use a hash table:

 my $flag = 0; my %aa = (); $aa{$_} = 1 foreach (@a); foreach my $i (@b) { if ($aa{$i}) { $flag = 1; last; } } 

If big n - |@a| + |@b| > ~1000 |@a| + |@b| > ~1000 |@a| + |@b| > ~1000 items

0
source share

IMHO, you should use List :: MoreUtils :: in pairs . However, if for some reason you cannot, then the next sub will return 1 for each index, where the value in the first array is compared with the value in the second array. You can generalize this method as much as you want, and pass your own comparator if you want, but at this point just set List :: MoreUtils will be a more productive use of your time.

 use strict; use warnings; my @a = qw(abc def ghi jkl); my @b = qw(abc dgh dlkfj jkl kjj lkm); my $map = which_ones_equal(\@a, \@b); print join(', ', @$map), "\n"; sub which_ones_equal { my ($x, $y, $compare) = @_; my $last = $#$x > $#$y ? $#$x : $#$y; no warnings 'uninitialized'; return [ map { 0 + ($x->[$_] eq $y->[$_]) } $[ .. $last ]; } 
0
source share

This is Perl. The β€œobvious” solution:

 my @a = qw"abc def efg ghy klm ghn"; my @b = qw"def ghy jgk lom com klm"; print "arrays equal\n" if @a == @b and join("\0", @a) eq join("\0", @b); 

if "\ 0" is not in @a.

But thanks for confirming that there is no other generic solution, except that you skated on your own.

0
source share
 my @a1 = qw|abcd|; my @a2 = qw|bcde|; for my $i (0..$#a1) { say "element $i of array 1 was not found in array 2" unless grep {$_ eq $a1[$i]} @a2 } 
0
source share

If you think arrays with a different order are different, you can use Array :: Diff

 if (Array::Diff->diff(\@a, \@b)->count) { # not_same } else { # same } 
0
source share

This question can still mean two things that say: β€œIf any element matches, then set the flag”:

  1. Elements in the same position, that is, $ a [2] eq $ b [2]
  2. Values ​​at any position, that is, $ a [3] eq $ b [5]

For case 1, you can do this:

 # iterate over all positions, and compare values at that position my @matches = grep { $a[$_] eq $b[$_] } 0 .. $#a; # set flag if there any match at the same position my $flag = 1 if @matches; 

For case 2, you can do this:

 # make a hash of @a and check if any @b are in there my %a = map { $_ => 1 } @a; my @matches = grep { $a{$_} } @b; # set flag if there matches at any position my $flag = 1 if @matches; 

Please note that in the first case, @matches contains indices where there are matching elements, and in the second case, @matches contains matching values ​​in the order in which they appear in @b.

0
source share

All Articles