如何比较文本文件中最后一列应该相同的连续行?并且倒数第二列中至少有一个值必须不匹配。
- 首先比较文件中的第6列,如果匹配的话
- 然后比较第 4 列中的匹配行。第 4 列中的所有值不应相同,至少有一个值应不同。这里 HSF1 和 HIF1AN 位于第 1、2、3 行。
输入文件
chr10 102979 103832 HSF1 305
chr10 102979 103832 HIF1AN 1 305
chr10 102979 103832 HSF1 305
chr10 103124438 103124851 HSF1 471
chr10 103124438 103124851 EGLN1 2 471
chr10 103969896 103970503 HSF1 472
chr10 103969896 103970503 HSF1 472
chr10 39135037 39142175 HSF1 335
chr10 4191461 4191936 HSF1 309
chr10 4191461 4191936 HSF1 309
chr10 42423355 42424014 HSF1 336
输出文件
chr10 102979 103832 HSF1 305
chr10 102979 103832 HIF1AN 1 305
chr10 102979 103832 HSF1 305
chr10 103124438 103124851 HSF1 471
chr10 103124438 103124851 EGLN1 2 471
答案1
假设一个制表符分隔的文件,您可以使用 GNU awk:
gawk -F'\t' 'NR == FNR {count[$6][$4]++; next} length(count[$6]) > 1' file file
chr10 102979 103832 HSF1 305
chr10 102979 103832 HIF1AN 1 305
chr10 102979 103832 HSF1 305
chr10 103124438 103124851 HSF1 471
chr10 103124438 103124851 EGLN1 2 471
这会遍历文件两次:第一次计算每个 $6 出现了多少个 $4 值;如果该 $6 有超过 1 个 $4 值,则第二次输出记录。
它可能可以在一次传递中完成,但代价是复杂性、内存使用量以及可能丢失原始顺序。
Perl 中的相同逻辑
perl -Mautodie -e '
open $f, "<", shift;
while (<$f>) {
@F = split /\t/;
$c{ $F[5] }{ $F[3] }++;
}
# re-process the file
seek $f, 0, 0;
while (<$f>) {
@F = split /\t/;
print if scalar keys %{ $c{$F[5]} } > 1;
}
' file
答案2
逐行读取文件,如果最后一列与缓冲区中所有其他行的值相同,则将该行存储在缓冲区中,否则处理缓冲区并将其清空。
处理缓冲区意味着尝试找到至少一对不共享第四列值的连续行,如果成功则打印缓冲区。
我将确切的行与各个列一起存储在缓冲区中,以获得更好的输出并更容易访问值。
#!/usr/bin/perl
use warnings;
use strict;
sub process {
my (@rows) = @_;
my $different;
for my $i (1 .. $#rows) {
$different = 1, last if $rows[ $i - 1 ][4] ne $rows[$i][4];
}
print map "$_->[0]\n", @rows if $different;
}
my @buffer;
while (<>) {
chomp;
my @columns = split;
if (! @buffer || $buffer[0][-1] == $columns[-1]) {
push @buffer, [$_, @columns];
} else {
process(@buffer);
@buffer = [$_, split];
}
}
process(@buffer);