Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing two arrays and finding differences

I need to compare two array and get differences.

Background:

1st array will list out files in folder.

2nd array will read the content of a file and stored in array.

The output of 1st array will be

a
b
c
d
e

The output of 2nd array will be

a
b
c
e

How I can compare those 2 array that get differences? The finale output that I want is

d

Here is the code:

#!/usr/bin/perl

use strict;
use warnings;

my $list  = "experiment.sv";
my $path  = "../../../folder1/";
my $filelist;

open ( OUTFILE, ">output.txt" );
main ();
close OUTFILE;


sub main {

   my @array1;
   opendir ( DIR, $path ) || die "Error in opening dir $path\n"; 
   while ( $filelist = readdir (DIR) ) {
       next if ( $filelist =~ s/\.//g);   #/
       push @array1, $filelist;         
   }
   closedir(DIR);

   my @array2;
   open( my $fh, "<", "$path/$list") or die "Failed to open file: $!\n";   
   while(<$fh>) { 
      push @array2, $_;                  
   } 
   close $fh;

   my @result;
   foreach my $array2 (@array2) {
       foreach my $array1 (@array1) {
           if ($array1 !~ /$array2/ ) {
               push @result, "$array1\n";
           }
       }
   }

   print OUTFILE "",@result;  

}
like image 721
daffodil Avatar asked Dec 22 '22 22:12

daffodil


1 Answers

There are a few ways to do this, also depending on what exactly is needed.

Using an ancillary hash for each array, to reduce the existence check to a lookup

use warnings;
use strict;
use feature 'say';

sub diff_arys {
    my ($ra1, $ra2) = @_;

    my %in_a1 = map { $_ => 1 } @$ra1;
    my %in_a2 = map { $_ => 1 } @$ra2;

    my @not_in_one = grep { not exists $in_a1{$_} } @$ra2;
    my @not_in_two = grep { not exists $in_a2{$_} } @$ra1;

    return (@not_in_one ? \@not_in_one : undef), 
           (@not_in_two ? \@not_in_two : undef);
}

my @ary1 = 'a'..'e';         # a,b,c,d,e
my @ary2 = ('a'..'d', 'z');  # a,b,c,d, z
    
my ($not_in_one, $not_in_two) = diff_arys(\@ary1, \@ary2);

say "@$not_in_one"  if $not_in_one;
say "@$not_in_two"  if $not_in_two;

Prints

z
e

This finds difference both ways, elements in one array but not in the other. If you know for fact that you only need it for one "direction," to identify things that are in the first array but not in the second (as it seems from the question), then adjust the sub so to only get needed return. Then there's less code, and you can just return the array (so, a list or empty)

Note the choice for the interface: Return undef if no difference is found, an arrayref otherwise.

There are good modules for this kind of work. A rather comprehensive one is List::Compare. There are also Array::Utils and Array::Compare, and yet more. And then there are more complex tools that can also be used for this, like Algorithm::Diff.

like image 75
zdim Avatar answered Jan 05 '23 01:01

zdim