【问题标题】:Find lines with the same columns' pairs in one file在一个文件中查找具有相同列对的行
【发布时间】:2016-01-22 05:13:26
【问题描述】:

假设我有这个制表符分隔的文件

id1 term1 term2
id2 term1 term2
id3 tern2 term3

我想要做的是在它们引用的 ID 旁边计算相同 column2 column3 出现的次数。

所以新的制表符分隔文件将如下所示:

term1 term2 2 id1,id2
term2 term3 1 id3

我已经尝试过这种单线,这是我最接近所需解决方案的方法

awk '{count[$2,$3]++;} END {for (word in count) printf("%s\t%s\n", word,count[word])}'

但我得到的是:

term1 term2 2
term2 term3 1

在术语之间是一个矩形。

任何关于 Perl 或 awk 或其他任何东西的想法都会很可爱。

起初我认为 Perl 会更好,但我的一个朋友建议使用 awk。这是我第一次使用 awk。

【问题讨论】:

  • “起初我认为 Perl 会更好,但我的一个朋友建议使用 awk。这是我第一次使用 awk。” Perl 会做 awk 可以做的所有事情,包括用 Perl 编写简洁的单行代码更难的例外。你应该坚持你所知道的。任何推荐 awk 而不是 Perl 的人都是粉丝

标签: regex bash perl awk


【解决方案1】:

这个解决方案按你的要求做

数组@pairs的唯一目的是保留输入数据的顺序。如果没有必要,那么代码可以大大减少

我假设给定的第 2 列/第 3 列值对可能会以相同的 ID 出现多次。这意味着我必须分别计算这对的出现次数,而不是累积相关的 ID。如果不是这样,那么计数就是每对的 ID 数

use strict;
use warnings;
use feature 'say';

my %pairs;
my @pairs;

while ( <> ) {

    chomp;
    my ($id, $pair) = split "\t", $_, 2;

    push @pairs, $pair unless $pairs{$pair};

    ++$pairs{$pair}{count};
    $pairs{$pair}{ids}{$id} = 1;
}

for my $pair ( @pairs ) {
    my ($n, $ids) = @{ $pairs{$pair} }{qw/ count ids /};
    say join "\t", $pair, $n, join(',', keys %$ids);
}

输出

term1 term2 2   id1,id2
tern2 term3 1   id3

【讨论】:

  • 展示了 Perl 中的实现。你说得对,一位朋友说不是选择awk 而不是perl 的理由。使用awk 的一个原因是这样的算法可以在awk 中很好且简短地表达,而且damn! 很快。
  • 短算法不是美德
  • @Sobrique 是正确的。简洁是一种美德,而不仅仅是简洁。
  • 嗯。如果您关心代码文件中每行 80 个字符,通常几个字符可以产生影响。但是,我当然不会说这是 规则。例如,这个问题根本不是一个单行,所以在这种情况下无关紧要。
  • 哇,谢谢!这比我要求的还要多!我唯一好奇的是这些:$pairs{$pair}{count}我明白你在做什么,这是可行的,但这正常吗?我的意思是你能用哈希表做这样的事情吗?
【解决方案2】:

你可以使用awk:

awk -f script.awk input.file

script.awk 看起来像这样:

{
    # Select and count the terms combination
    terms=$2" "$3
    count[terms]++

    # Concatenate ids by `,` - except if it
    # is the first occurrence
    ids[terms]=ids[terms] ? ids[terms]","$1 : $1
}
END{
    # At the end print the desired results
    for(terms in count){
        print terms,count[terms],ids[terms]
    }
}

【讨论】:

  • 这忽略了ID可能重复给定数据对的可能性
  • @Borodin id 通常是唯一的。这就是目的。
  • 是的,对于一组数据中的每条记录,ID 应该是唯一的。但是我们不知道这些数据的结构,除非每条记录只包含显示的两列,否则很可能 ID 在这个子集中重复
  • 好吧,如果这真的很重要,我们可以简单地在将 id 添加到 ids 之前添加一个条件,并检查它是否已经添加。但是这个问题并没有反映那个atm。
  • @EdMorton 你的建议看起来不错。让我明天玩弄它,并可能添加它。我今天很喜欢......
【解决方案3】:

使用 GNU awk 实现真正的二维数组:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ ids[$2 FS $3][$1] }
END {
    for (key in ids) {
        printf "%s\t%s", key, length(ids[key])
        sep = OFS
        for (i in ids[key]) {
            printf "%s%s", sep, i
            sep = ","
        }
        print ""
    }
}
$ awk -f tst.awk file
tern2   term3   1       id3
term1   term2   2       id1,id2

【讨论】:

    猜你喜欢
    • 2018-05-07
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 2016-01-27
    • 2010-12-19
    相关资源
    最近更新 更多