【问题标题】:Perl: Matching columns from two different filesPerl:匹配来自两个不同文件的列
【发布时间】:2016-12-21 14:34:18
【问题描述】:

(注意:列标题是为了便于阅读,而不是在实际文件中)

文件 1

COLUMN1         COLUMN2   COLUMN3
AG_446337835.1  example1  grgsdt
AG_448352465.1  example2  190197
AG_449465753.1  example3  h837h8
AG_449366462.1  example4  d34tw4
AG_444725037.1  example5  f45ge4
AG_441227463.1  example6  f3fw4t
AG_449986090.1  example7  gft7r4
AG_445666926.1  example8  4vsr55
AG_441004541.1  example9  fh893b
AG_444837264.1  example0  k3883d

文件 2

COLUMN1  COLUMN2
grgsdt   AAHG
h837h8   JUJN
190197   POKJ
f45ge4   DFRF
gft7r4   NNHN
d34tw4
fh893b  YUNIP
k3883d  YUNIP
f3fw4t  YUNIP
190197  YUNIP
4vsr55  GHGF

所需的输出文件

COLUMN1         COLUMN2   COLUMN3 COLUMN4 (formerly column2 from file2)
AG_446337835.1  example1  grgsdt  AAHG 
AG_448352465.1  example2  190197  POKJ  YUNIP
AG_449465753.1  example3  h837h8  JUJN
AG_449366462.1  example4  d34tw4  
AG_444725037.1  example5  f45ge4  DFRF
AG_441227463.1  example6  f3fw4t  YUNIP
AG_449986090.1  example7  gft7r4  NNHN
AG_445666926.1  example8  4vsr55  GHGF
AG_441004541.1  example9  fh893b  YUNIP
AG_444837264.1  example0  k3883d  YUNIP

我对 Perl(或一般编程)几乎不熟悉,我想知道您是否介意就这个问题向我提出建议。

基本上,file1 中的第 3 列对应于 File2 中的第 1 列。

我想获取 file1 中的每一行,读取该行的第 3 列,在 file2 中搜索匹配条目,如果存在匹配条目,则将 file1 中的行和文件 2 中的额外列打印到新文件(如所示在示例输出中)。

文件大小为

文件 1:2GB

文件2:718MB

此脚本将在具有 250GB 内存的机器上运行,因此内存不是问题。

这是我目前所拥有的

#!/usr/bin/perl ;
#use warnings;

use Getopt::Long qw(GetOptions);
use experimental 'smartmatch';
#Variable to store inputted text file data
my $db ;
my $db2 ;




#Open and read File one into memory
open FPIN, "file1.txt" or die "Could not open";
my @file1 = <FPIN> ;
close FPIN;

#Open and read file two into memory
open FPIN, "file2.tab" or die "Could not open";
my @file2 = <FPIN> ;
close FPIN ;




foreach (@file2)
  {
    if (/(^\w+)\t(.+)/)
      { 
        split /\t/, $2; 
        $db2->{$1}->{"geneName"} = $1 ;
        $db2->{$1}->{"protein"} = $2 ;
      }             

  }

foreach (@file1)
    {
      #if line begins with any word character tab and anything
      if (/(^\w+.\d+)\t(.+)/)
        { 
            my @fields = split /\t/, $2;
            my $refSeqID = $1;

           #assign the data in the array to variables
            my ($geneSymbol, $geneName) = @fields[0, 1];

          #Create database data structure and fill it with the info
            $db->{$2}->{"refSeqID"} = $refSeqID ;
            $db->{$2}->{"geneSymbol"} = $geneSymbol ;
            $db->{$2}->{"geneName"} = $geneName ;

       }
   }         

foreach my $id (sort keys %{$db2}) 
  {
    if ( exists $db->{$id} )
      {   
        print $db2->{$id}."\t".$db->{$id}->{$geneSymbol}."\t".$db->{$id}-> 
        {$refSeqID}."\t".$db2->{$id}->{$protein}."\n";
      }

  }

我似乎能够正确地将这两个文件读入内存。 但是,我完全无法将这些文件相互比较,我对如何处理它感到震惊。

实际上打印它将是我需要解决的另一个问题。

【问题讨论】:

  • 列标题是文件的一部分吗?
  • 不,我只是为了可读性添加了这些。我将编辑该信息。

标签: perl bigdata


【解决方案1】:

按照你的要求做

首先读取file2.txt 并构建一个哈希%f2,将第一列的值与第二列的值关联起来

此后,只需阅读file1.txt,将其拆分为多个字段,并添加通过使用第三个字段的值访问哈希获得的进一步字段

我使用autodie 来省去处理open 调用中的错误的麻烦。否则一切都是标准的

更新

我刚刚注意到file2.txt 中可能会重复第 1 列的值,因此我更改了代码以使散列的每个键对应于一个 array 值。数组中的所有值都以空格分隔的形式出现在输出的第 4 列中

use strict;
use warnings 'all';
use autodie;

my %f2;

{
    open my $fh, '<', 'file2.txt';
    while ( <$fh> ) {
        my ($key, $val) = split;
        $f2{$key} //= [];
        push @{ $f2{$key} }, $val if $val;
    }
}

open my $fh, '<', 'file1.txt';

while ( <$fh> ) {
    my @line = split;
    my $c4 =  $f2{$line[2]};
    push @line, $c4 ? join(' ', @$c4) : '';
    local $" = "\t";
    print "@line\n";
}

输出

AG_446337835.1  example1    grgsdt  AAHG
AG_448352465.1  example2    190197  POKJ YUNIP
AG_449465753.1  example3    h837h8  JUJN
AG_449366462.1  example4    d34tw4  
AG_444725037.1  example5    f45ge4  DFRF
AG_441227463.1  example6    f3fw4t  YUNIP
AG_449986090.1  example7    gft7r4  NNHN
AG_445666926.1  example8    4vsr55  GHGF
AG_441004541.1  example9    fh893b  YUNIP
AG_444837264.1  example0    k3883d  YUNIP

【讨论】:

  • 成功了。我不能开始感谢你,但无论如何我都会开始。谢谢!
【解决方案2】:

这个是left join。关键思想是使用geneName 作为哈希中的键。

#! /usr/bin/perl
use strict;
use warnings;

my %data = ();

open $a, "file1";
while (<$a>) {
    chomp;
    my @c = split;
    $data{$c[2]} = [$c[0], $c[1], $c[2]];
}

open $b, "file2";
while (<$b>) {
    chomp;
    my @c = split;
    push @{$data{$c[0]}}, exists $c[1] ? $c[1] : "";
}

print map { "@{$_}\n" } values %data;

【讨论】:

  • 如果您解释一下为什么您认为“左连接”更好,将会有所帮助。
  • 我错了。你也做了一个左连接。两个答案都是一样的。
猜你喜欢
  • 2020-07-20
  • 1970-01-01
  • 2021-10-01
  • 2020-04-28
  • 1970-01-01
  • 2015-05-07
  • 2014-11-27
  • 2015-09-19
  • 2018-04-02
相关资源
最近更新 更多