以相反的顺序枚举

时间:2013-12-05 13:17:05

标签: python perl awk

cat dummy_file
    A   ID1  
    A   ID2   
    A   ID3
    B   ID4
    B   ID5
    C   ID6
    C   ID7
    C   ID8
    C   ID9

awk命令按照第一列列出并枚举dummy_file个项目。

 awk '{count[$1]++}; {print $0"\t"count[$1]}' dummy_file
    A   ID1  1
    A   ID2  2
    A   ID3  3
    B   ID4  1
    B   ID5  2
    C   ID6  1
    C   ID7  2
    C   ID8  3
    C   ID9  4

如何为输出反转枚举count[$1]++(以相反顺序枚举),如下所示:

    A   ID1  3
    A   ID2  2
    A   ID3  1
    B   ID4  2
    B   ID5  1
    C   ID6  4
    C   ID7  3
    C   ID8  2
    C   ID9  1

3 个答案:

答案 0 :(得分:3)

IF 输入文件确实在第一列上排序,正如您在示例中所示,并且您想要“按照排序顺序排列第一列的索引号”,然后:

awk '
   (NR==FNR) { occured[$1]++ ; next ; } 
             {print $0,occured[$1]--; }
    ' dummy_file dummy_file

这是一个非常常见的“双循环”,即我们读取文件两次,并使用“NR == FNR”区分第一遍。

上面的awk程序:1)在第一次传递时,增加(默认为0)第一列上看到的每个事物的出现次数。并跳过其余部分转到下一行。 2)在同一文件的第二次传递:输出该行,在其后添加第一列的“剩余出现”。

给出OP的当前示例文件:

$ awk '
      (NR==FNR) { occured[$1]++ ; next ; } 
                {print $0,occured[$1]--; }
      ' dummy_file dummy_file

A   ID1 3
A   ID2 2
A   ID3 1
B   ID4 2
B   ID5 1
C   ID6 4
C   ID7 3
C   ID8 2
C   ID9 1

可以根据需要调整输出的实际显示,以保持/简化/更改间距等。

答案 1 :(得分:2)

与Olivier相同的解决方案,但在Perl中。读取文件,使用带有-a开关的autosplit开关-F拆分选项卡上的每一行,以设置特定的分隔符。将元素存储在数组@a中,将哈希值作为第一个元素的计数器。读完文件后,浏览数组,打印元素,并在递减时打印散列计数器。

perl -F'\t' -anle 'push @a, [ @F ]; $x{$F[0]}++; 
                   END { print join("\t", @$_, $x{$_->[0]}--) for @a }'

<强>输出:

A       ID1     3
A       ID2     2
A       ID3     1
B       ID4     2
B       ID5     1
C       ID6     4
C       ID7     3
C       ID8     2
C       ID9     1

答案 2 :(得分:1)

假设输入是按第一个字段排序的:此解决方案仅使用一次传递,将数据临时存储在数组中,然后在遇到密钥或文件结尾更改时打印和清除内容:

[rev_enum.awk $] cat reverse_enumerate.awk
#!/bin/gawk -f

BEGIN{idx=1}
NF==2 {
    if(key!=$1){
        print_and_clear();
    }
    data[idx]=$0;
    idx++;
    key=$1;
}
function print_and_clear()
{
    n=length(data);
    for(i=1; i<=n; i++){
        print data[i] " " n-i+1;
    }
    idx=1;
    delete data;
}
END{print_and_clear();}
[rev_enum.awk $] cat dummy_file
    A   ID1
    A   ID2
    A   ID3
    B   ID4
    B   ID5
    C   ID6
    C   ID7
    C   ID8
    C   ID9[rev_enum.awk $]
[rev_enum.awk $] ./reverse_enumerate.awk dummy_file
    A   ID1 3
    A   ID2 2
    A   ID3 1
    B   ID4 2
    B   ID5 1
    C   ID6 4
    C   ID7 3
    C   ID8 2
    C   ID9 1
[rev_enum.awk $]

也许这对某些人有用。 :/

为了完整起见,这是一个不假设文件按第一列排序的解决方案。显然,这会将整个文件缓存在内存中,这对于大文件来说可能是禁止的。

#!/bin/gawk -f 
BEGIN{idx=1}
NF==2{
    if($1 in data){
    data[$1]=data[$1]","$2;
    }else{
    order[idx++]=$1;
    data[$1]=$2;
    }    
}

END{
    n=length(order);
    for(i=1;i<=n;i++){
        m=split(data[order[i]], temp,",");
    for(j=1;j<=m;j++){
        print order[i] " " temp[j]" " m-j+1;
    }
    }
}
相关问题