如何比较和合并多个文件?
How to compare and merge multiple files?
参考文件
chr1 288598 288656
chr1 779518 779576
chr2 2569592 2569660
chr3 5018399 5018464
chr4 5182842 5182882
文件1
chr1 288598 288656 12
chr1 779518 779576 14
chr2 2569592 2569660 26
chr3 5018399 5018464 27
chr4 5182842 5182882 37
file2
chr1 288598 288656 35
chr2 2569592 2569660 348
chr3 5018399 5018464 4326
chr4 5182842 5182882 68
我有六个类似的文件,不包括参考文件。
此处前三个字段与参考文件相似。因此,我只想从所有 6 个文件中导出第 4 列并放入参考文件中以生成新的输出。这应该等同于参考文件。他们不匹配的地方放零。
期望输出
chr1 288598 288656 23 35 57 68 769 68
chr1 779518 779576 23 0 57 68 768 0
chr2 2569592 2569660 23 35 0 68 79 0
chr3 5018399 5018464 0 36 0 68 769 0
chr4 5182842 5182882 23 0 0 0 0 0
注意:参考文件的长度约为 2000,而其他文件的长度并不总是相同(大约 500、400、200、100 等)。这就是为什么需要添加零。
我尝试了 this question
的答案
paste ref.file file1 file2 file3 file4 file5 file6 | awk '{OFS="\t";print ,,,,,,,,}' > final.common.out
但它似乎不起作用 — 遗漏了一些值。而且我不明白如何在没有匹配项的地方加零。
我认为像这样的东西应该可以满足您的需求。我们使用散列来收集 'reference' 文件并将其转换为一组具有空数组的键。
然后我们迭代其他文件,提取“3 个值”作为键,最后一个值作为实际值。
然后我们比较两者,用值或零更新 'reference' 散列。这里的警告 - 参考文件中的任何 not 行(或重复行)都将消失。
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
#read 'reference file' into a hash:
my %ref;
open( my $ref_fh, "<", "reference_file" );
while (<$ref_fh>) {
my ( $first, $second, $third ) = split;
#turn the first three fields into space delimited key.
$ref{"$first $second $third"} = ();
}
#open each of the files.
my @files = qw ( file1 file2 file3 file4 file5 file6 );
foreach my $input (@files) {
open( my $input_fh, "<", $input );
my %current;
while (<$input_fh>) {
#line by line, extract 'first 3 fields' to use as a key.
#then 'value' which we store.
my ( $first, $second, $third, $value ) = split;
$current{"$first $second $third"} = $value;
}
#refer to 'reference file' and insert matching value or zero into
#the array.
foreach my $key ( keys %ref ) {
push( @{ $ref{$key} }, $current{$key} ? $current{$key} : 0 );
}
}
foreach my $key ( keys %ref ) {
print join( " ", $key, @{ $ref{$key} } );
}
参考文件
chr1 288598 288656
chr1 779518 779576
chr2 2569592 2569660
chr3 5018399 5018464
chr4 5182842 5182882
文件1
chr1 288598 288656 12
chr1 779518 779576 14
chr2 2569592 2569660 26
chr3 5018399 5018464 27
chr4 5182842 5182882 37
file2
chr1 288598 288656 35
chr2 2569592 2569660 348
chr3 5018399 5018464 4326
chr4 5182842 5182882 68
我有六个类似的文件,不包括参考文件。
此处前三个字段与参考文件相似。因此,我只想从所有 6 个文件中导出第 4 列并放入参考文件中以生成新的输出。这应该等同于参考文件。他们不匹配的地方放零。
期望输出
chr1 288598 288656 23 35 57 68 769 68
chr1 779518 779576 23 0 57 68 768 0
chr2 2569592 2569660 23 35 0 68 79 0
chr3 5018399 5018464 0 36 0 68 769 0
chr4 5182842 5182882 23 0 0 0 0 0
注意:参考文件的长度约为 2000,而其他文件的长度并不总是相同(大约 500、400、200、100 等)。这就是为什么需要添加零。
我尝试了 this question
的答案paste ref.file file1 file2 file3 file4 file5 file6 | awk '{OFS="\t";print ,,,,,,,,}' > final.common.out
但它似乎不起作用 — 遗漏了一些值。而且我不明白如何在没有匹配项的地方加零。
我认为像这样的东西应该可以满足您的需求。我们使用散列来收集 'reference' 文件并将其转换为一组具有空数组的键。
然后我们迭代其他文件,提取“3 个值”作为键,最后一个值作为实际值。
然后我们比较两者,用值或零更新 'reference' 散列。这里的警告 - 参考文件中的任何 not 行(或重复行)都将消失。
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
#read 'reference file' into a hash:
my %ref;
open( my $ref_fh, "<", "reference_file" );
while (<$ref_fh>) {
my ( $first, $second, $third ) = split;
#turn the first three fields into space delimited key.
$ref{"$first $second $third"} = ();
}
#open each of the files.
my @files = qw ( file1 file2 file3 file4 file5 file6 );
foreach my $input (@files) {
open( my $input_fh, "<", $input );
my %current;
while (<$input_fh>) {
#line by line, extract 'first 3 fields' to use as a key.
#then 'value' which we store.
my ( $first, $second, $third, $value ) = split;
$current{"$first $second $third"} = $value;
}
#refer to 'reference file' and insert matching value or zero into
#the array.
foreach my $key ( keys %ref ) {
push( @{ $ref{$key} }, $current{$key} ? $current{$key} : 0 );
}
}
foreach my $key ( keys %ref ) {
print join( " ", $key, @{ $ref{$key} } );
}