Perl:如果值数组相交,则从 2 个散列中打印键

Perl: Print keys from 2 hashes if array of values intersect

我有 2 个文件,如下所示:

File1:除最后一列外的所有列均以制表符分隔

space   start   end width   names   score.data  
1   1   1873    24409   22537   DDX11L1 NA
2   1   4361    39370   35010   WASH7P  NA
23  1   690244  724068  33825   LOC100288069    NA
24  1   742750  765214  22465   FAM87B  "rs1;rs2;rs3,"
25  1   751585  772902  21318   LINC00115   "rs3;rs4"
26  1   752970  804826  51857   LINC01128   "rs5;rs6;rs7;rs8;rs9"
27  1   793450  822182  28733   FAM41C  "rs9;rs10;rs11"
28  1   842197  865072  22876   LOC100130417    "rs12;rs13;rs14;rs15;rs16"
29  1   851120  889961  38842   SAMD11  "rs14;rs15;rs16;rs17"
30  1   869582  904679  35098   NOC2L   "rs13;rs17;rs20;rs25;rs27"  
31  1   885966  911099  25134   KLHL17  "rs23;rs25;rs34;rs49"
78  1   1582938 1634243 51306   SLC35E2B    rs45

File2:除最后一列外,所有列均以制表符分隔

space   start   end width   names   score.data  
1   1   1096679 1097517 839     DMR1 rs2;rs3  
2   1   1229025 1229590 566     DMR2 rs4  
3   1   1267955 1269432 1478    DMR3 rs7;rs8;rs9  
4   1   1279248 1279795 548     DMR4 rs9;rs10  
5   1   1372628 1374653 2026    DMR5 rs11;rs12;rs14;rs18  
6   1   1842116 1842456 341     DMR6 NA  
7   1   1896556 1897211 656     DMR7 rs13;rs17;rs20  

所需输出:所有列均以制表符分隔

DMR1 FAM87B LINC00115   
DMR2 LINC00115    
DMR3 LINC01128 FAM41C    
DMR4 LINC01128 FAM41C
DMR5 FAM41C LOC100130417 SAMD11
DMR7 SAMD11 NOC2L 

所以基本上,我需要检查来自 file2 的任何 score.data 条目(rs2、rs3...)是否与 file1score.data 条目相交。如果他们这样做,我应该从 file2 获得密钥(names column)并从 file1 获得相应的密钥(names column)。

例如 file2 中的 DMR1 有 score.data rs2;rs3FAM87B 的 score.data rs1;rs2;rs3 相交并且 [= =27=] LINC00115file 1

到目前为止,我编写的大部分代码都涉及清理“”和 NA 条目的第一个文件并创建哈希:

use 5.014;
use warnings;

my $file1 = '/path/to/file1';
my $file2 = '/path/to/file2';

#Open files
open my $fh1 , '<', $file1 or die $!;
open my $fh2, '<', $file2 or die $!;


#Read file1
my %gene_hash;
while(<$fh1>){
    chomp;
    my @arr = split; 
    next if $arr[0] eq "space";
    next if $arr[6] eq 'NA';

    my $key = $arr[5]; #Hash key

    my @snps = split /;/, $arr[6]; #to be used as value in hash
    my $first_snp = shift @snps; #remove 1st element from start

    my @first_snp = split /"/, $first_snp; #remove " from start
    unshift @snps, $first_snp[1]; #add 1st element back to beginning


    my $last_snp = pop @snps; #remove last element
    my @last_snp = split /"/, $last_snp; #remove " from end

    push @snps, $last_snp[0];# add last element back to the end
    push @snps, $arr[6] if $arr[6] =~/^rs.*/; #add element even if there are no "" eg SLC35E2B

    push @{ $gene_hash{$key} }, @snps; #assign values to hash
}



my %dmr_hash;
while(<$fh2>){
   chomp;
   my @arr = split;

   next if $arr[0] eq "space";
   next if $arr[6] eq 'NA';

   my $key = $arr[5]; #Hash key

   my @snps = split /;/, $arr[6];#to be used as value in hash
   push @{ $dmr_hash{$key} }, @snps; #assign values to hash

}  

我尝试在 Whosebug 上搜索其他哈希比较问题,所有这些问题在两个哈希中都有相同的键。我还找到了 Array::Utils 工具来交叉两个数组,但我真的不确定如何在我的问题中实现它。

感谢您抽出时间回答我的问题,我将不胜感激您的想法和解决方案。

这将按照您的要求进行。它构建一个散列 %mapping 将每个分数条目与它们在 File1 中对应的所有名称相关联,然后在读取 File2 时询问该散列以构建由分数条目

连接的名称列表

程序期望两个输入文件的路径作为命令行上的参数,例如

请注意,我刚刚在空白处拆分了每条记录,因为您的示例数据中的分隔符不一致

DRM7 的输出包括您想要的输出中缺少的 LOC100130417。这是正确的,因为 File2 中的 DRM7 有分数条目 rs13,它也出现在 File1

中的 LOC100130417 行中
perl find_joined.pl path/to/file1 path/to/file2
use strict;
use warnings;
use v5.10.1;
use autodie;

my %mapping;

{
    open my $fh, '<', $ARGV[0];
    <$fh>; # Drop the header line

    while ( <$fh> ) {
        my @fields = split;
        my $name = $fields[-2];
        my @entries = $fields[-1] =~ /[^";]+/g;
        push @{ $mapping{$_} }, $name for @entries;
    }

    delete $mapping{NA};
}

open my $fh, '<', $ARGV[1];
<$fh>; # Drop the header line

while ( <$fh> ) {
    my @fields = split;
    my $name = $fields[-2];
    my @entries = $fields[-1] =~ /[^";]+/g;

    my %matching;
    @matching{@$_} = () for grep defined, @mapping{@entries};

    if ( keys %matching ) {
        print join(' ', $name, sort keys %matching), "\n"
    }
}

输出

DMR1 FAM87B LINC00115
DMR2 LINC00115
DMR3 FAM41C LINC01128
DMR4 FAM41C LINC01128
DMR5 FAM41C LOC100130417 SAMD11
DMR7 LOC100130417 NOC2L SAMD11