compare columns from 2 files & print matching and non-matching rows in same order as in file1 & print YES/NO at end of matching and non-matching rows

Viewed 88

file1

3 14573 ab712 A T
8 12099 ab002 G A
9 12874 ab790 A C
3 19879 ab734 G T

file2

3 14573 ab712 A T
9 12874 ab790 A C

output

3 14573 ab712 A T YES
8 12099 ab002 G A NO
9 12874 ab790 A C YES
3 19879 ab734 G T NO

I tried perl foreach loop on file1 & 2
output generated is as follows-

3 14573 ab712 A T YES
8 12099 ab002 G A NO
9 12874 ab790 A C NO
3 19879 ab734 G T NO
4 34565 ab992 C G NO
9 12874 ab790 A C YES
3 14573 ab712 A T NO
8 12099 ab002 G A NO
9 12874 ab790 A C NO
3 19879 ab734 G T NO
4 34565 ab992 C G NO

Script I tried

foreach $arr1 (@arr1) {
  chomp $arr1;
  ($chr1, $pos1, $id1, $ref1, $alt1) = split(/\t/, $arr1);

  foreach $arr2 (@arr2) {
    chomp $arr2;  
    ($chr2, $pos2, $id2, $ref2, $alt2) = split(/\s/, $arr2);

    {
      if (($pos1 eq $pos2 ) && ($chr1 eq $chr2 )) {
        print "$chr1\t$pos1\t$ref1\t$alt1\tYES\n";
      } else {
        print "$chr1\t$pos1\t$ref1\t$alt1\tNO\n"
      }  
    }   
  }
}  
2 Answers

Your code is rather complex, so I'm afraid I don't have time to understand it and correct whatever you're doing wrong.

I do, however, have time to present my solution (with comments):

#!/usr/bin/perl

# Always use these
use strict;
use warnings;

# Open file2...
open my $fh2, '<', 'file2' or die $!;

# ... and use its contents to construct a hash.
# The key of the hash is the line of data from the
# file (without the newline) and the value is the
# number 1.
# We can therefore use this hash to work out if a
# given line from file1 exists in file2.

my %file2 = map { chomp; $_ => 1 } <$fh2>;

# Open file1...
open my $fh1, '<', 'file1' or die $!;

# ... and process it a line at a time
while (<$fh1>) {
  # Remove the newline
  chomp;
  # Print the line
  print;
  # Find out if the line exists in file2
  # and print 'YES' or 'NO' as appropriate.
  print $file2{$_} ? ' YES' : ' NO';
  # Print a newline.
  print "\n";
}

Update: Here's a version that only matches on the first two fields of the input data (that shouldn't matter given the sample input, but your code implies that's what you want to match on).

#!/usr/bin/perl

# Always use these
use strict;
use warnings;

# Open file2...
open my $fh2, '<', 'file2' or die $!;

# ... and use its contents to construct a hash.
# The key of the hash is the first two fields from
# the line of data from the file and the value is the
# number 1.
# We can therefore use this hash to work out if a
# given line from file1 exists in file2.

my %file2 = map { join(' ', (split)[0,1]) => 1 } <$fh2>;

# Open file1...
open my $fh1, '<', 'file1' or die $!;

# ... and process it a line at a time
while (<$fh1>) {
  # Remove the newline
  chomp;
  # Print the line
  print;
  # Find out if the line exists in file2
  # and print 'YES' or 'NO' as appropriate.
  print $file2{join ' ', (split)[0,1]} ? ' YES' : ' NO';
  # Print a newline.
  print "\n";
}

You could read file2 into a hashmap and use it to lookup the entries in file1.

Example:

#!/usr/bin/perl

use strict;
use warnings;
use Path::Tiny;

my @file1 = path("file1")->lines;
chomp @file1;
my %file2 = map {chomp; $_ => 1} path("file2")->lines;

for my $line (@file1) {
    print "$line " . (defined($file2{$line}) ? 'YES' : 'NO') . "\n";
}

If only the first and second column should be involved in the comparison:

#!/usr/bin/perl

use strict;
use warnings;
use Path::Tiny;

my @file1 = path("file1")->lines;
chomp @file1;
my %file2 = map {my @f = split; $f[0].' '.$f[1] => 1} path("file2")->lines;

for my $line (@file1) {
    my @f=split/\s+/,$line;
    print "$line " . (defined($file2{$f[0].' '.$f[1]}) ? 'YES' : 'NO') . "\n";
}

Output in both cases:

3 14573 ab712 A T YES
8 12099 ab002 G A NO
9 12874 ab790 A C YES
3 19879 ab734 G T NO
Related