Perl 在文件内进行比较,然后在文件之间进行比较

Perl 在文件内进行比较,然后在文件之间进行比较,perl,Perl,文件1: col1 col2 col3 col4 col5 col6 col7 col8 chr1 1361651 1361652 1 3 0 1 chr1 1421915 1421916 1 0 0 chr1 3329147 3329148 2,3 0 1 1 chr1 8421092 8421093 3 1,2,3 1 chr1 13802362 13802363 3 1,2,3 1 1 chr1 43315088 43315089 2 1,2 1 0 chr1 52256664 52256

文件1:

col1 col2 col3 col4 col5 col6 col7 col8 chr1 1361651 1361652 1 3 0 1 chr1 1421915 1421916 1 0 0 chr1 3329147 3329148 2,3 0 1 1 chr1 8421092 8421093 3 1,2,3 1 chr1 13802362 13802363 3 1,2,3 1 1 chr1 43315088 43315089 2 1,2 1 0 chr1 52256664 52256665 2 1,3 1 0 1 文件2:

col1 col2 col3 col4 col5 col6 col7 col8 chr1 1361651 1361652 1 3 0 0 1 chr1 1421915 1421916 1 1 1 0 0 chr1 3329147 3329148 2 2,3 0 1 1 chr1 8421092 8421093 3 1,2,3 1 1 1 chr1 13802362 13802363 3 1,2,3 1 1 1 chr1 43315088 43315089 2 1,2 1 1 0 chr1 52256664 52256665 2 1,3 1 0 1 col1 col2 col3 col4 col5 col6 col7…..col16 chr1 1361651 1361652 G数据5数据6数据7…数据16 chr1 2468066 2468067 G数据5数据6数据7…数据16 chr1 3329147 3329148。。。。。。。。 chr1 8421092 8421093。。。。。。。。 chr1 13802362 13802363。。。。。。。。 chr1 43315088 43315089。。。。。。。。 chr1 52256664 52256665。。。。。。。。 Output.txt

检查文件1的第5列是否有1,2,3,然后比较文件1和文件2之间的第1列和第2列,并在单独的文件中打印匹配项

col1 col2 col3 col4 col5 col6 col7.....col16 chr1 1361651 1361652 G data5 data6 data7....data16 chr1 2468066 2468067 G data5 data6 data7....data16 chr1 3329147 3329148 ........ chr1 8421092 8421093 ........ chr1 13802362 13802363 ........ chr1 43315088 43315089 ........ chr1 52256664 52256665 ........ col1 col2 col3 col4 col5 col6 col7…..col16 chr1 8421092 8421093。。。。。。。。 chr1 13802362 13802363。。。。。。。。 我的代码帮助我比较两个文件,但首先我需要比较文件中的,然后比较整个文件

col1 col2 col3 col4 col5 col6 col7.....col16 chr1 8421092 8421093 ........ chr1 13802362 13802363 ........
my$file1=$ARGV[0];
my$file2=$ARGV[1];
打开(FILE1,$FILE1);
打开(FILE2,$FILE2);
打开我的$f、“>”、“output.txt”或“无法打开output.txt:$!”;
我的@arr1=;
我的@arr2=;
关闭文件1;
关闭文件2;
对于(@arr1)
{
咀嚼;
my($hit1、$hit2、$hit3、$hit4、$hit5、$rest)=拆分(/\t/);
my$ckey=“$hit1\\$hit2”;
$chash{$ckey}=1;
}
对于(@arr2)
{
咀嚼;
我的($val1,$val2,$val3,$val4,$val5,$rest)=拆分(/\t/);
my$ckey=“$val1\\\$val2”;
$chash{$ckey}++;
如果($chash{$ckey}==2)
{
#此密钥已在以前的两个文件中看到
打印$f“$\n”;
}
}

您的描述有点模棱两可-暂且不勾选“1,2,3”-您的描述谈到比较第1列和第2列,但第1列在两个文件中的每一行上都有相同的内容-即“chr”。由于您突出显示了第2列和第3列中的数字,以及它们出现在“Output.txt”文件中,我想您指的是这两列,而不是1和2,这是我继续讨论的基础

在讨论解决方案之前,我只想强调一下现有代码中的几个问题——首先,您将两列串接在一起。如果第2列和第3列在一个文件中分别有“46”“123”,该怎么办;另一个是它的“461”&“23”,那么你的concat会给你一个错误的匹配。现在也许,这是“不可能发生的”,如果你对你的数据非常了解,那就足够公平了——但你需要意识到这种可能性

更重要的是,对前面看到的数字进行哈希跟踪不足以完成您需要的任务-如果在同一文件的第2列和第3列中有两行内容相同,会发生什么情况?如果一个文件中有两行内容相同,而另一个文件中有一行内容相同,会发生什么情况,总共给出3个,但你只想得到2个?。同样,您可能知道这些组合不会出现在您的数据中,但您需要注意潜在的bug

还有一件事——不清楚(至少对我来说)第2列和第3列的匹配是否必须分别位于每个文件的同一行。在您的测试数据中,第4行和第5行上的第2列和第3列分别与另一个文件中的第4行和第5行匹配-这是必要的吗?或者,(再一次,把“1,2,3”这件事放在一边一分钟)第一个文件第4行的第2列和第3列能否与第二个文件第7行的第2列和第3列相匹配

我并不想在这里感到困难,但显然,这些事情与找到正确的解决方案非常相关

如果您希望对现有代码进行最低限度的更改,因为我指出的这些事情都无关紧要,那么您所需要做的就是“退出”第一个循环,除非“1,2,3”在第5列中,即
$arr1[4]
或-在拆分之后-
$hit5
。好吧,就加上这个

my $file1 = $ARGV[0];
my $file2 = $ARGV[1];
open(FILE1, $file1);
open(FILE2, $file2);
open my $f, '>', "output.txt" or die "Cannot open output.txt: $!";
my @arr1=<FILE1>;
my @arr2=<FILE2>;
close FILE1;
close FILE2;
for (@arr1)
{
    chomp;
    my($hit1,$hit2,$hit3,$hit4,$hit5,$rest)=split(/\t/);
    my $ckey="$hit1\_$hit2";
    $chash{$ckey}=1;
}
for (@arr2)
{
    chomp;
    my($val1,$val2,$val3,$val4,$val5,$rest)=split(/\t/);
    my $ckey="$val1\_$val2";
    $chash{$ckey}++;
    if( $chash{$ckey} == 2 )
    {
    # this key has been seen in both previous files
    print $f "$_\n";
    }
}

显示的代码有点太复杂了。此外,如果文件之间的任何单词恰好相同,则不清楚哈希将如何处理。此外,还需要保持整条线,并与比赛地点相协调。您需要额外的数据结构。这里有一个更简单的方法

将每行的前两个字段连接起来,并将该字符串放入数组中。在通过
file1
的同时,也要检查条件,如果没有找到,则退出。为
文件2
形成并存储相同的字符串,还存储整行。然后遍历任一数组的索引,当字符串匹配时,选择
file2
的对应行(根据需要)。这些线是我们的输出。代码可以更简单,请参见注释

问题:1)找到“1,2,3”是一个条件——如果没有找到,请不要麻烦,这是正确的吗?2) 两个文件中的第1列在示例中的给定值相同。。。它们不同吗?3) 一旦找到匹配项,是否保证(匹配项的)整行相等?4) 书写行的顺序重要吗?@zdim,问题:1)正确2)它们不同3)如果找到匹配项,请完整打印文件2行4)顺序不重要文件中是否有(合法)空字段?如果答案是“否”,你可以在我的答案中使用更简单的版本。如果答案是“不,决不”,我可能应该删除带有检查等的零件。如果数据可能更混乱(缺少各种字段),则应该进行更多检查。请
chomp;
my($hit1,$hit2,$hit3,$hit4,$hit5,$rest)=split(/\t/);
next unless $hit4 eq "1,2,3";   # <-- Added line
my $ckey="$hit1$hit2";
$chash{$ckey}=1; 
#!/usr/bin/env perl
use v5.12;

my $file1 = $ARGV[0];
my $file2 = $ARGV[1];
open(FILE1, $file1) or die "$file1: $!\n";
open(FILE2, $file2) or die "$file2: $!\n";
open my $f, '>', "output.txt" or die "Cannot open output.txt: $!";

my @arr1 = map [split(" ", $_)], <FILE1>;
my @arr2 = map [split(" ", $_)], <FILE2>;
close FILE1;
close FILE2;

my $i = 0;
for my $arr1row (@arr1) {
    # Grab the same row in file 2
    my $arr2row = $arr2[$i++] ;

    # bail unless we have "1,2,3" in col 5
    next unless $arr1row->[4] eq "1,2,3" ;

    # bail if we dont have a line from file 2 because its shorter
    next unless defined $arr2row ;

    # If col2 and col3 are the same from each file ...
    if ($arr1row->[1] == $arr2row->[1] &&
        $arr1row->[2] == $arr2row->[2] )  {

        # print out all fields from file 2
        say $f join("\t", @$arr2row);
    }
}
use warnings;
use strict;

my $patt = '1,2,3';

# Join cols 1,2 into a string, store; check condition
open my $fh1, '<', 'file1.txt';
my @f1;
my $go = 0;
while (my $line = <$fh1>) {
    next if $line =~ /^\s*$/;
    my @cols = split '\s+', $line;
    my ($c1, $c2) = @cols[0,1];
    next if not $c1 or not $c2;
    push @f1, join '_', $c1, $c2;
    $go = 1 if $cols[4] and $patt eq $cols[4];
}
close $fh1;

if (not $go) {
    print "Condition not satisfied, exiting.\n";    
    exit 0;
}

# Join cols 1, 2 from file2, store; store lines
my (@f2, @lines);
open my $fh2, '<', 'file2.txt';
while (<$fh2>) {
    next if /^\s*$/;
    my ($c1, $c2) = (split)[0,1];
    next if not $c1 or not $c2;
    push @f2, join('_', $c1, $c2);
    push @lines, $_;
}
close $fh2;

# Find matches: compare strings from arrays
# Print corresponding lines file2
my @output;
foreach my $i (0..$#f2) {
    push(@output, $lines[$i]) if $f1[$i] eq $f2[$i];
} 
print "$_\n" for @output;
col1 col2 col3 col4 col5 col6 col7 col8 chr1 1361651 1361652 G data5 data6 data7....data16 chr1 3329147 3329148 ........ chr1 8421092 8421093 ........ chr1 13802362 13802363 ........ chr1 43315088 43315089 ........ chr1 52256664 52256665 ........
while (<$fh1>) {
    next if /^\s*$/;
    my ($c1, $c2, $c4) = (split)[0,1,4];
    push @f1, join '_', $c1, $c2;
    $go = 1 if $patt eq $cols[4];
}
exit if not $go;
while (<$fh2>) {
    next if /^\s*$/;
    push @f2, join '_', (split)[0,1];
    push @lines, $_;
}
@output = map { $lines[$_] } grep { $f1[$_] eq $f2[$_] } (0..$#f2);