2016-11-28 5 views
1

2つの列しか持たないディレクトリに多数の(数十)TSVファイルがあります。両方を最初の列の値に基づいてマージします(両方の列には保守が必要なヘッダーがあります) );この値が存在する場合は、対応する2番目の列の値などを追加する必要があります(例を参照)。ファイルは異なる行数を持ち、最初の列では順序付けされていないかもしれませんが、これはソートで簡単に行えます。最初の列で多くのTSVファイルをマージする

私は試しましたに参加しましたが、これは2つのファイルに対してうまく機能します。ディレクトリ内のすべてのファイルに対して結合を拡張できますか?私はawkが良い解決策かもしれないと思うが、awkの知識は非常に限られている。何か案は?ここで

はわずか3ファイルの例です:

S01.tsv 

Accesion S01 
AJ863320 1 
AM930424 1 
AY664038 2 

S02.tsv 

Accesion S02 
AJ863320 2 
AM930424 1 
EU236327 1 
EU434346 2 

S03.tsv 

Accesion S03 
AJ863320 5 
EU236327 2 
EU434346 2 

OUTFILEは次のようになります。

Accesion S01 S02 S03 
    AJ863320 1  2  5 
    AM930424 1  1 
    AY664038 2 
    EU236327   1  2 
    EU434346   2  2 

OK、ジェームス・ブラウンのおかげで、私が働いて、このコードを持って(私はそれがcompile.awk命名)

BEGIN { OFS="\t" }       # tab separated columns 
FNR==1 { f++ }        # counter of files 
{ 
    a[0][$1]=$1        # reset the key for every record 
    for(i=2;i<=NF;i++)      # for each non-key element 
     a[f][$1]=a[f][$1] $i (i==NF?"":OFS) # combine them to array element 
} 
END {           # in the end 
    for(i in a[0])       # go thru every key 
     for(j=0;j<=f;j++)      # and all related array elements 
      printf "%s%s", a[j][i], (j==f?ORS:OFS) 
}            # output them, nonexistent will output empty 

私は

として実際のファイルでそれを実行しました:いくつかの不具合で
awk -f compile.awk 01.tsv 02.tsv 03.tsv 

私はのような出力が得られます。ファイルには、すべてのファイルのヘッダ(ライン3)から始めるべき最初の2つの行が属していない

LN854586.1.1236   1 
JF128382.1.1303  1 
Accesion S01 S02 S03 
JN233077.1.1420 1  
HQ836180.1.1388  1 
KP718814.1.1338   1 
JQ781640.1.1200   2 

。 これを修正する方法はありますか?

+0

は、あなたがこれまでにしようとしているものを(問題の)を示しことができます? – agold

+0

基本的に参加し、grepを試してみました。同様のものを探していましたが、コーディングの知識が不足しているため実装や変更ができませんでした。結合は、私が欲しいものを正確に行いますが、2つのファイルだけを処理します。 – BrunoGG

+0

'program.awk'は次のリンクから利用できます。あなたの必要に応じて 'OFS'を修正してください(' OFS = "\ t" '私は仮定します)。また、出力レコードの順序はランダムです。 http://stackoverflow.com/questions/40373180/bash-combining-files-into-csvs/40408764#40408764 –

答えて

2

私はおそらくそれをこのような何かに取り組むでしょう:あなたの入力を考えると

#!/usr/bin/perl 
use strict; 
use warnings; 
use Data::Dumper; 

my @header; 
my %all_rows; 
my %seen_cols; 


#read STDIN or files specified as args. 
while (<>) { 
    #detect a header row by keyword. 
    #can probably do this after 'open' but this way 
    #means we can use <> and an arbitrary file list. 
    if (m/^Accesion/) { 
     @header = split;  
     shift @header; #drop "accession" off the list so it's just S01,02,03 etc. 
     $seen_cols{$_}++ for @header; #keep track of uniques. 
    } 
    else { 
     #not a header row - split the row on whitespace. 
     #can do /\t/ if that's not good enough, but it looks like it should be. 
     my ($ID, @fields) = split; 
     #use has slice to populate row. 

     my %this_row; 
     @this_row{@header} = @fields; 

     #debugging 
     print Dumper \%this_row; 

     #push each field onto the all rows hash. 
     foreach my $column (@header) { 
     #append current to field, in case there's duplicates (no overwriting) 
     $all_rows{$ID}{$column} .= $this_row{$column}; 
     } 
    } 
} 

#print for debugging 
print Dumper \%all_rows; 
print Dumper \%seen_cols; 

#grab list of column headings we've seen, and order them. 
my @cols_to_print = sort keys %seen_cols; 

#print header row. 
print join "\t", "Accesion", @cols_to_print,"\n"; 
#iteate keys, and splice. 
foreach my $key (sort keys %all_rows) { 
    #print one row at a time. 
    #map iterates all the columns, and gives the value or an empty string 
    #if it's undefined. (prevents errors) 
    print join "\t", $key, (map { $all_rows{$key}{$_} // '' } @cols_to_print),"\n" 
} 

を - 除外デバッグに - 印刷物:

Accesion S01 S02 S03 
AJ863320 1 2 5 
AM930424 1 1  
AY664038 2   
EU236327  1 2 
EU434346  2 2 
+0

このperlスクリプトは、魅力のように動作します!私はちょうど(#)最終版のために、感謝の印刷ラインをコメントします。 – BrunoGG

関連する問題