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
答案 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;
}
}
}