我有一个制表符分隔文件,如下所示:
Het 157709 157731 Cluster.90 2 +
Het 157739 157760 Cluster.90 2 +
Het 164238 164259 Cluster.97 10 +
Het 164380 164401 Cluster.97 10 +
Het 164396 164417 Cluster.97 10 +
Het 164397 164421 Cluster.97 10 +
Het 164397 164420 Cluster.97 10 +
Het 164399 164420 Cluster.97 10 +
Het 164536 164561 Cluster.97 10 +
Het 164576 164598 Cluster.97 10 +
Het 164599 164615 Cluster.97 10 +
Het 164635 164656 Cluster.97 10 +
Het 198007 198031 Cluster.125 3 +
Het 198007 198028 Cluster.125 3 +
Het 198011 198035 Cluster.125 3 +
我正在寻找一种有效的方法来生成如下文件:
Het 157709 157760 Cluster.90 2 +
Het 164238 164656 Cluster.97 10 +
Het 198007 198035 Cluster.125 3 +
对于第4列中的每个唯一条目,我写了一行,其中包括第1列和第2列的第一行,后面是第3,4,5和6列中的最后一行。到目前为止,我已经尝试了以下解决方案但效率似乎很低:
for i in `awk '{print $4}' filename | sort | uniq`
do
fgrep -F $i -w filename | awk 'NR==1 {printf $1"\t"$2"\t"} END {print $3"\t"$4"\t"$5"\t"$6}' >>filename2
done
问题是,当我有一个巨大的文件(487559行)时,这需要永远。是否有更好的解决方案隐藏在某人的脑袋里?
答案 0 :(得分:3)
只有第4列中的唯一条目在第5列到末尾始终具有相同的数据时,此单行才会起作用。你的例子是这样的,但我似乎并没有真正回答这个问题。不过,FWIW:
paste <(uniq -f3 file | cut -f1,2) <(tac file | uniq -f3 | tac | cut -f3-)
uniq
有一个选项,可以控制要比较唯一性的字符数,以及要跳过的前导字段数和要跳过的前导字符数,但不包括要比较的字段数。
答案 1 :(得分:1)
这可以在单个awk中完成,这将比你的脚本更有效:
awk '!($4 in a){a[$4]=$1 FS $2; r[++i]=$4; b[$4]=$3 FS $4 FS $5 FS $6; next;} {b[$4]=$3 FS $4 FS $5 FS $6; next} END{for (k=1; k<=i; k++) print a[r[k]], b[r[k]]}' OFS='\t' file
Het 157709 157760 Cluster.90 2 +
Het 164238 164656 Cluster.97 10 +
Het 198007 198035 Cluster.125 3 +
使其可读:
awk '!($4 in a){
a[$4]=$1 FS $2;
r[++i]=$4;
b[$4]=$3 FS $4 FS $5 FS $6;
next;
}
{
b[$4]=$3 FS $4 FS $5 FS $6;
next;
}
END {
for (k=1; k<=i; k++)
print a[r[k]], b[r[k]]
}' OFS='\t' file
答案 2 :(得分:1)
以下是awk
的另一种方式:
awk '
!seen[$4]++ {
col[$4] = $1 FS $2;
fld[++i] = col[$4]
}
{
sub(/([^ ]+ +){2}/,x);
line[i] = fld[i] FS $0
}
END {
for(x = 1; x <= i; x++)
print line[x]
}' OFS='\t' file
输出:
Het 157709 157760 Cluster.90 2 +
Het 164238 164656 Cluster.97 10 +
Het 198007 198035 Cluster.125 3 +
答案 3 :(得分:0)
您的代码很慢,因为您为每个组启动了fgrep
和awk
个进程。
您可以在第4列排序后,一次性处理整个文件,当然,您已经知道该怎么做。
所以只需用bash,python,ruby,perl,awk或你选择的任何语言来编写,这些语言从stdin逐行读取,并在第4列中记录最后看到的值。每当这个值发生变化时,做你需要的do:写出包含前两列中第一个看到的值以及后面列中最后看到的值的行。然后记录第1列和第2列的新值。它非常简单,但在第一行和最后一行可能会很棘手。