0

我想根据多列中的匹配过滤行。我有(各种)4 列制表符分隔的文件。我需要检查第 1 列中的所有重复项,检查相应的第 4 列,如果值不同(即使仅出现一次)打印整行(4 列)。

这是输入的示例:

function-n  such_as-handheld-n  6.4623  A
function-n  such_as-hash-n  6.5328  A
party-n such_as-head-n  2.5586  A
function-n  such_as-headphone-n 8.0794  B
function-n  such_as-health-n    3.1938  A
party-n such_as-heartbeat-n 6.5902  B
party-n such_as-heat-n  3.9708  B
zebra-n at-1-aquatic-n  10.0476 B
zebra-n become-pelican-n    12.4166 B
zebra-n behind-idea-of-concept-n    16.0319 B
zebra-n move-lion-n 12.2017 B
zebra-n such_as-1-pole-n    8.9519  B
zebra-n try-reasoning-n 12.9504 B
zooplankton-n   than-1-mangrove-n   12.0638 B

因此结果如下:

function-n  such_as-handheld-n  6.4623  A
function-n  such_as-hash-n  6.5328  A
party-n such_as-head-n  2.5586  A
function-n  such_as-headphone-n 8.0794  B
function-n  such_as-health-n    3.1938  A
party-n such_as-heartbeat-n 6.5902  B
party-n such_as-heat-n  3.9708  B

因为“function-n”和“party-n”是 Column1 中唯一在第 4 列中具有不同值的值。

我在此处使用 awk看到了有关基于多列丢弃行的帖子。代码(由@Steve 提出)如下:

FNR==NR {
    array[$0]++
    next
}

{
    counter = 0
    for (i in array) {
        split(i, holder, FS)
        if (holder[1] == $1) {
            counter++
        }
    }
    if (counter >= 2) {
        print
    }
}



$ awk -f script.awk file.txt{,}

这段代码完全符合我的需要,除了 2 列数据。我试图修改脚本的一部分来比较第 4 列,如下所示:

{
    counter = 0
    for (i in array) {
        split(i, holder, FS)
        if (holder[1] == $4) {
            counter++
        }

然而,它不起作用。谁能提供有关如何修改此脚本的见解,以便我可以达到预期的结果?

或者也许有人有更有效/优化的方式来处理问题?谢谢你。

4

2 回答 2

2

我认为你必须非常努力地使用 awk。在阅读完每一行之前,您无法开始打印,而且我认为您需要的数据结构在某种程度上超出了 awk 提供的范围。您可以使用更高级的语言:想到 Python、Perl、Ruby。

这是红宝石 1.9.3:

ruby -F"\t" -ane '
    BEGIN { 
        f4 = Hash.new {|h,k| h[k] = Hash.new} 
        lines = Hash.new {|h,k| h[k] = Array.new} 
    }
    f4[$F[0]][$F[-1]] = 1
    lines[$F[0]] << [$., $_]
    END {
        output = []
        f4.each_pair do |key, subhash|
            if subhash.length > 1
                lines[key].each {|pair| output[pair[0]] = pair[1]}
            end
        end
        puts output
    }
'

珀尔:

perl -F"\t" -ane '
    $f4{$F[0]}{$F[-1]} = 1;
    push @{$lines{$F[0]}}, [$., $_];
    END {
        @output=();
        while (($key, $subhash) = each %f4) {
            if (keys(%$subhash) > 1) {
                $output[$_->[0]] = $_->[1] for @{$lines{$key}};
            }
        }
        print @output;
    }
'
于 2013-10-23T17:01:10.827 回答
0

一个可能的解决方案(使用 awk)如下:

$ awk 'NR==FNR { if(A[$1]!=$NF && A[$1]){B[$1]++} A[$1]=$NF; next }\
  { if(B[$1]){ print } }' input input > output

于 2013-10-24T09:01:17.387 回答