比较文件中最后一列相同但另一列不同的行

比较文件中最后一列相同但另一列不同的行

如何比较文本文件中最后一列应该相同的连续行?并且倒数第二列中至少有一个值必须不匹配。

  1. 首先比较文件中的第6列,如果匹配的话
  2. 然后比较第 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);

相关内容