0

我有一些文件,如下所示

GLL  ALM  654-656  654  656 
SEM  LYG  655-657  655  657
SEM  LYG  655-657  655  657 
ALM  LEG  656-658  656  658 
ALM  LEG  656-658  656  658  
ALM  LEG  656-658  656  658  
LEG  LEG  658-660  658  660 
LEG  LEG  658-660  658  660

GLL 的值为 654。ALM 的值为 656。同理,第 4 列代表第一列的值。第五列代表第二列的值。我想计算第四列和第五列中每个数字的唯一出现次数。

期望的输出

654 GLL 1
655 SEM 1
656 ALM 2
657 LYG 1
658 LEG 2
660 LEG 1
4

3 回答 3

1

如果我正确理解您的问题,此脚本可以为您提供输出:

awk '{d[$4]=$1;d[$5]=$2;p[$4];l[$5]}
END{
    for(k in p){
        if (k in l){
            delete l[k]
            print k,d[k],"2"
        }else
        print k,d[k],"1"
    }
    for (k in l)
        print k, d[k],1
} ' file

使用您的输入数据,上述脚本的输出:

654 GLL 1
655 SEM 1
656 ALM 2
658 LEG 2
657 LYG 1
660 LEG 1

所以它与您的预期输出(订单)不是 100% 相同,但如果您将它传送到sort -n,它会给您完全相同的东西。排序部分也可以在 awk 中完成。我有点懒... :)

于 2013-07-22T08:53:59.423 回答
0

我的看法:

sort -u file |
awk '
    BEGIN {SUBSEP = OFS}
    {count[$4,$1]++; count[$5,$2]++}
    END {for (key in count) print key, count[key]}
' |
sort -n
654 GLL 1
655 SEM 1
656 ALM 2
657 LYG 1
658 LEG 2
660 LEG 1
于 2013-07-22T10:42:51.110 回答
0

抱歉,它太长了,但是如果发生这种情况,它可以工作并且内置奖励!有关详细信息,请参阅编辑 2。:-)

awk '
BEGIN { SUBSEP = FS;
    before = 0;
    between = 1;
    after = 0;
}

{
    offset = int((NF - after - before - between) / 2) + between;
    for (i=1 + before; i <= offset + before - between; i++) {
        j = i + offset;
        if (! ((i, $j, $i) in entry))
            entry[i, $j, $i]++;
    }
}

END {
    for (item in entry) {
        split(item, itema);
        entry[itema[2], itema[3]]++;
        delete entry[item];
    }
    for (item in entry)
        print item, entry[item];
}' filename | sort -n

第一部分过滤输入,只接受应该在输出的第一列和第二列中的唯一出现的对。第二部分合并结果,在唯一列中每次出现加 1(例如 LEG,658 在 $1,$4 和 $2,$5 中都至少出现一次,因此计算两次),并打印结果,通过到 sort 实用程序以对输出进行数字排序。

它适用于 N 对,因此如果您将来有类似以下的内容,脚本仍然可以工作,只要只添加对(您不能添加另一个单独的字段,否则脚本会中断):

GLL  ALM  LEG  654-660  654  656  660

我想如果你愿意,你可以在开头添加额外的字段并更改 i 的起始值。或者,可以在末尾添加并从 i 的最终值中再减去您添加的每个新字段(例如,如果您在末尾添加 1 个未配对字段,则为 NF - 2)。这将需要重新设计以适应中间的未配对值,因为数据集将完全不同。

编辑 之所以这么长,是因为它很灵活(有点),而且我还是个 awk 新手。如果您不喜欢我的,我会推荐 Kent's(或者它不起作用——我目前没有使用安装了 awk 的计算机)。

编辑 2 更新的脚本。它以前不起作用,现在它可以处理任意偏移量,只要没有未配对的字段将配对分开。类似以下的工作:

GLL ALM LYG 654-657 654 656 657
SEM LYG 655-657 655 657
SEM LYG LEG 655-660 655 657 660
ALM LEG 656-658 656 658
LEG LEG 658-660 658 660
LYG LEG 657-660 657 660

输出:

654 GLL 1
655 SEM 1
656 ALM 2
657 LYG 3
658 LEG 2
660 LEG 2

编辑 3 该脚本现在处理任意连续的未配对字段。您必须配置在一对的第一部分开始之前有多少个字段(例如,在该行的第一个 GLL、ALM 等之前有多少个字段),对的第一部分和第二部分之间有多少个字段,以及后面有多少个字段对的第二部分的列表。请注意,它必须是连续且一致的,这意味着您不能在一行的第一对开始组件之前有 1 个字段,在另一行的第一对开始组件之前不能有 5 个字段,并且您不能有一对开始/end 组件与另一个相同的组件分开(例如,“GLL xyz ALM 654 656”不起作用,因为“xyz”将“GLL”和“ALM”分开,它们都是对开始组件)。

除此之外,还需要有关数据集的实际知识,例如 GLL 是否可能紧随其后有额外的信息,但 ALM 从来没有这样的数据。

于 2013-07-22T08:55:10.387 回答