重叠脚本:如何解决?

Overlooping script: how to solve?

我写了一个简单的代码来匹配两个文件中的 select/discard 元素。 此代码适用于 $file_in,其中包含对 Id:

Id1 Id2
Id1 Id3
Id1 Id4
Id3 Id4
Id3 Id5
Id3 Id6
Id4 Id5
Id4 Id6

并且在 $file_list 上包含一个 Id 列表:

Id1
Id2
Id4
Id6
Id7
Id8

我想要的是获得一个输出,其中仅报告来自 $file_in 的对,这两个 Id 都包含在 $ 中file_list。 因此,我想要的输出如下:

Id1 Id2
Id1 Id4
Id4 Id6

我正在使用的代码在 $file_in 中重叠并给出了这个输出:

 Id1 Id2
 Id1 Id2
 Id1 Id4
 Id1 Id2
 Id1 Id4
 Id4 Id6
 Id1 Id2
 Id1 Id4
 Id4 Id6
 Id1 Id2
 Id1 Id4
 Id4 Id6

代码如下:

use List::MoreUtils qw(any);

$file_in = "gold_standards.txt";
$file_list = "list.txt";

open (HAN, "< $file_in") || die "Impossible open the in-file...";

my @r = <HAN>;
close (HAN);

open (PEW, "< $file_list") || die "Impossible open list_file...";
@l = <PEW>;
close (PEW);

for ($p=0; $p<=$#l; $p++){
chomp ($l[$p]);

for ($i=0; $i<=$#r; $i++){
    chomp ($r[$i]);     
    @v = split (/\t/, $r[$i],2);
        $id_protein1 = $v[0];
        $id_protein2 = $v[1];


    if ((any {$id_protein1 eq $_} @l) && (any {$id_protein2 eq $_} @l)) {
        print "$r[$i]\n";    
    }
}
}

我确定这是一个基本问题,但目前我无法修复它。感谢任何帮助。

您还可以循环遍历第一个文件,并将您想要的任何字段作为散列键放入散列中。然后遍历第二个文件,如果该字段在哈希中,则将匹配的键打印到输出文件。您不必同时打开两个文件,也不必同时逐一执行每个文件。

***重写我的散列想法和@jhnc 的想法

use warnings;
use strict;

open (PEW,"<","list.txt") or die "Cannot open list_file...";
my @l = <PEW>;
close (PEW);
chomp @l;

my %lh = map { $_ => 1} @l;

open (HAN,"<","gold_standards.txt" ) or die "Cannot open the in-file...";
while (<HAN>) {
   chomp;
   my ($id_protein1, $id_protein2) = split(/ /, $_);
   print "$_\n" if (exists $lh{$id_protein1} and exists $lh{$id_protein2});
}
close (HAN);

翻转 2 个 for 循环的顺序,然后在找到匹配项后立即使用 last 退出内部循环。这就是您在输出中出现重复项的原因。

use warnings;
use strict;
use List::Util qw(any);

my $file_in   = "gold_standards.txt";
my $file_list = "list.txt";

open( HAN, "< $file_in" ) || die "Impossible open the in-file...";
my @r = <HAN>;
close(HAN);
chomp @r;

open( PEW, "< $file_list" ) || die "Impossible open list_file...";
my @l = <PEW>;
close(PEW);
chomp @l;


for ( my $i = 0 ; $i <= $#r ; $i++ ) {
    my @v           = split( /\s+/, $r[$i], 2 );
    my $id_protein1 = $v[0];
    my $id_protein2 = $v[1];
    for ( my $p = 0 ; $p <= $#l ; $p++ ) {
        if ( ( any { $id_protein1 eq $_ } @l ) && ( any { $id_protein2 eq $_ } @l ) ) {
            print "$r[$i]\n";
            last;
        }
    }
}

我将 \t 更改为 \s+,因为当我复制您的输入文件时制表符显示为空格。

成功后立即切换循环嵌套和跳出内层循环,可以防止多次复制:

#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw(any);

$file_in = "gold_standards.txt";
$file_list = "list.txt";


open (HAN, "< $file_in") or die "Impossible open the in-file...";
my @r = <HAN>;
close (HAN);

open (PEW, "< $file_list") or die "Impossible open list_file...";
my @l = <PEW>;
close (PEW);

chomp (@l, @r);

for my $rv (@r) {
    my ($id_protein1, $id_protein2) = split(/\t/, $rv, 2);

    for my $lv (@l) {
        if ((any {$id_protein1 eq $_} @l) && (any {$id_protein2 eq $_} @l)) {
            print "$rv\n";    
            last;
        }
    }
}

根据@steveo314 的回答,您还可以在其中构建散列和查找:

# ...

my %lh = map { $_ => 1} @l;

for my $rv (@r) {
    my ($id_protein1, $id_protein2) = split(/\t/, $rv, 2);
    print "$rv\n" if (exists $lh{$id_protein1} && exists $lh{$id_protein2});
}

这是另一种将内容密钥存储在散列中并检查内容是否存在于散列中的方法。

参考以下代码:

#!/usr/bin/perl

use strict; use warnings;

my %list_hash;

my $file_in   = "gold_standards.txt";
my $file_list = "list.txt";

open (my $HAN, "<", $file_in) || die "Impossible open the in-file...";

my @r = <$HAN>;
close ($HAN);

open (my $PEW, "<", $file_list) || die "Impossible open list_file...";
my @l = <$PEW>;
close ($PEW);

foreach my $l_element (@l){
    chomp $l_element;
    $list_hash{$l_element} = 1;
}

foreach my $r_element( @r ){
    chomp $r_element;
    
    my @content = split(' ', $r_element);
        
    if(exists $list_hash{$content[0]} && exists $list_hash{$content[1]}){
        print "$r_element\n";
    }
}

一条线,多样化:

perl -lane 'if (!$#ARGV) { $h{$F[0]}++; next }
            if ($h{$F[0]} && $h{$F[1]}) { print }' file_list file_in