This is a test version of Biostars. For the public version, visit https://www.biostars.org.
Compare Columns In 2 Different File With Perl

Hi ,

I have tried to compare two tab delimited file contains different columns to find the match entries between two files but with my script i get nothing as output !

file 1 :

col1    col2   col3   col4   col5   col6 
 X       chrN  start   end    X      X

file 2 :

col1    col2   col3
chrN    start  end

I want to compare the Col2-3-4 in file1 with Col1-2-3 in file2 and printout the matched rows in file1

Thanks in Advance,

this is my script but i got nothing as output!

use strict;
use warnings;

open(FILE1,"<21minus.bed");
open(FILE2,"<enhancers.bed");
open (OUT,">outputfile.txt");

my @arr1=<FILE1>;
my @arr2=<FILE2>;

close FILE1;
close FILE2;

my %chash; 

for (@arr2){
chomp;
my($col1,$col2,$rest)=split(/\t/);
my $ckey="$col2$rest";
$chash{$ckey}=1;
}

for (@arr1){
chomp;
my($col1,$col2,$start,$end)=split(/\t/);
$start="" if(!$start); 
$end="" if(!$end); 
my $ckey="$start$end"; 
if($chash{$ckey}){ 
print OUT "$_\n"; 
}
}
perl comparison

Perhaps the command line would be better/quicker? cut -f2,3,4 file1.txt > ./newfile1.txt cut -f1,2,3 file2.txt > ./newfile2.txt diff newfile1.txt newfile2.txt > ./differences.txt

The parse differences.txt for your desired output. Just an idea.

Why are you discarding the chromosome id, and collapsing the coords into one contiguous number in generating the hashkey? I'd use foreach(@arr2){@F=split /t/, $; $ckey=join "-", @F[0..2]; $chash{$ckey}++} foreach(@arr1){@F=split /t/, $; $ckey=join "-", @F[0..2]; print $_ if exists $chash{$ckey}}

A plea to everyone. (1) Don't keep posting new questions as answers: edit your original question or use the comments or post links to code elsewhere if required. (2) Format code properly to make it readable (indent lines with 4 spaces).

It was pointed out at your re-post of this question that really, it is a basic Perl programming problem rather than a bioinformatics question. So in fairness, we have to close this as off-topic also. There are an awful lot of very basic errors in the code; it's not really fair for others to work through and fix them. I suggest you spend some time improving your basic skills in Perl - but feel free to keep asking questions with more relevance in bioinformatics.

6 answers

Perhaps the command line would be better/quicker?

cut -f2,3,4 file1.txt > ./newfile1.txt
cut -f1,2,3 file2.txt > ./newfile2.txt
diff newfile1.txt newfile2.txt > differences.txt

The exact options for the diff function are here.

Just an idea.

### In Response to Comment ###

If you save the below script as something.py then run as follows:

python something.py file2.txt file1.txt matches.txt

Your matches will be held in matches.txt. I just 'slapped' this together, but it should work fine if your files are not huge. Any issues, just drop me an email.

#! /usr/bin/python

import sys

inp = open(sys.argv[1], 'r')
file2 = [i.split() for i in inp.readlines()]
inp.close()

matches = []

inp = open(sys.argv[2], 'r')
file1 = inp.readline()
while file1:
    file1 = file1.split()
    if file1[1:4] in file2:
        matches.append(file1)
    file1 = inp.readline()

inp.close()

out = open(sys.argv[3], 'wt')
out.writelines('\t'.join(i) + '\n' for i in matches)
out.close()

that is good Idea but I am looking for equal values not the differences !

Or you try:

cut -f2-4 file1.txt | cat - file2.txt | sort | uniq -c | perl -ane 'print if($F[0]>1);'

But it only works, if your entries in each file are unique.

would something like this suit your idiom a bit more than the command line options given previously?

while($l1=<FILE1> && $l2=<FILE2>){
chomp $l2;
($f = $l2) =~ s/^(.*?\t.*?\t.*?\t).*$/$1/;
die if ! $f;
print $l1 if $l1 =~ /^$f.*$/;
}

I 'think' it should do what you want

EDIT: I don't think it does what you want

I dont know why none of commands and scripts work with my files ! nor my script!

I guess it's better to show you the head of files !

file 1 :

chr21 9411509 9411529 HWUSI-EAS1809:38:FC:4:46:12139:8182::1:N:0: 1 - 9411509 9411530 0,0,255 1 21 0

chr21 9417056 9417076 HWUSI-EAS1809:38:FC:4:86:7681:16695::1:N:0: 0 - 9417056 9417077 0,0,0 1 21 0

file 2 :

chr1 858256 858648 chr1:858256-858648 5 . 858447 858448 0,0,0 2 1,10 0,382

chr1 918449 918555 chr1:918449-918555 18 . 918504 918505 0,0,0 2 7,1 0,105

In these two files I tried to compare and find the match between columns 1-2-3 in file one and columns 1-2-3 in file two but I couldnt get the match output with my script and yours as well ! any other idea please ? I really stuck here for 3 days!

oh, so file2 doesn't look like I expected

That was my mistake cause I tried to explain it in easier way and it makes more problem :(

sorry

So its basically column 1,2,3 in file1 and column 1,2,3 in file 2. Is it??

yes the rest columns are not useful for my match comparisons

yes, just column 1,2,3 in file 1 and columns 1,2,3 in file 2 , as the rest columns are not useful for match comparison column 1 is chr number - column 2 is start position and column 3 is end position

Please do not post new questions as answers.

I tried to use your advise Varun but i still have problem , then I made another easier script but I got and error again!

this is my new script!

#!/usr/bin/perl

use strict; use warnings;

open my $fh1, '<', 'file1'; open my $fh2, '<', 'file2';

while ( defined( my $line1 = <$fh1> ) and defined( my $line2 = <$fh2> ) ) {

chomp($line1);

chomp($line2);

my @values1 = split( " ", $line1 );

my @values2 = split( " ", $line2 );

if ( $values1[0] eq $values2[0] and $values1[1] eq $values2[1] and $values1[2] eq $values2[2]) {print "$values2[0] t $values2[1] t $values2[2] t n" ;}}

close $fh1 ; close $fh2 ;

the error is : Use of uninitialized value in string eq at ./match3.pl line 13, <$fh2> line 11.

Use of uninitialized value in string eq at ./match3.pl line 13, <$fh2> line 12.

Use of uninitialized value in string eq at ./match3.pl line 13, <$fh2> line 13.

Use of uninitialized value in string eq at ./match3.pl line 13, <$fh2> line 14.

Use of uninitialized value in string eq at ./match3.pl line 13, <$fh2> line 15.

Use of uninitialized value in string eq at ./match3.pl line 13, <$fh2> line 16.

you have the head of two files in previous posts!

is their away here you can post your 2 files here i mean upload it somewhere and we can download and try to help you.

Varun

Hi, these are sample files i guess, not the complete files????

Moreover your file1 has blank spaces at the end of last lines remove them

I don't think this is the right way to go about your problem. a) you have to catch empty strings before your if; b) [and possibly my fault] this will only return data if line M in file1 matches with line M in file2; c) you're splitting a tab-delim'd file on spaces, not tabs.

Yes Varun I just copy the head of the files as sample file cause they're too big to upload them, I checked the file1 there is no spaces at the end of it! russH I change the script but I dont know how to catch the empty strings before if as you mentioned, I am not really expert in Perl.

Thanks again

Please do not post new questions as answers.

I am a perl one-liner. Check my command line:

$ cat 1.txt 
1   chr1    100 200 blahblah
2   chr2    50  100 blahblah
$ cat 2.txt
chr2    50  100
chr3    10  1000
$ perl -e 'open(I1,$ARGV[0]);open(I2,$ARGV[1]);while(<I2>){chomp;@_=split;$a{join("\t",$_[0],$_[1],$_[2])}=1;}while(<I1>){chomp;@_=split;print $_,"\n" if exists $a{join("\t",$_[1],$_[2],$_[3])}}' 1.txt 2.txt
2   chr2    50  100 blahblah

the thing that I want to get is, perhaps for ur examples:

$ cat 1.txt 
1   chr1    100 200 blahblah
2   chr2    50  100 blahblah
$ cat 2.txt
chr2    50  100
chr3    10  1000

output:

chr2 50 100

which both files have it!

Sorry there should be 'exists' instead of 'not exists'. I forgot to delete that word for debugging...

Log in to answer this question.