这更多的是寻找一个优雅的问题解决方案,我想我有一个可行的解决方案。我在 Ubuntu 机器上有以下输入文件格式(制表符分隔):
AC003665.1 17 47813266 AGCAGGCGCA 83
RIOK3 18 23453502 GCAAGGCCCC 52
UBE2Z 17 48910880 CTAAGGATCC 48
CSNK1D 17 82251379 AATTTAGCCA 68
CSNK1D 17 82251379 AATTTCTTGT 38
SMURF1 7 99143726 GACAGATTGG 74
SMURF1 7 99143726 GACAGATTGG 61
RIOK3 18 23453502 GCAAGACTTT 69
我只想在字段 3 的每次出现时获取一行,即字段 5 中具有最高值的一行。因此输出应该是:
AC003665.1 17 47813266 AGCAGGCGCA 83
CSNK1D 17 82251379 AATTTAGCCA 68
UBE2Z 17 48910880 CTAAGGATCC 48
SMURF1 7 99143726 GACAGATTGG 74
RIOK3 18 23453502 GCAAGACTTT 69
顺序与我的目的无关。我找到了一个解决方案,首先在字段 5 上排序,然后在字段 3 上排序,我认为该解决方案有效:
sort -k 5,5nr input | sort -u -k 3,3n > output
它适用于我的所有测试文件,我认为在任何情况下都应该适用,因为这应该确保对于字段 3 的每个值,排序将首先看到(并因此保留)字段 5 具有最高值的行。
然而,我觉得应该有一个更优雅(也许更万无一失)的解决方案来解决这个问题?任何帮助表示赞赏。
答案1
如果要输出的数据足够小以适合内存,那么
awk '
biggest[$3] < $5 { biggest[$3]=$5 ; saved[$3]=$0 }
END { for (i in saved) { print saved[i] }}'
一般来说,这会更快,在决定是否需要存储时,需要查看每一行一次。内存要求是针对输出的数据的,因此非常重复的输入可能会非常巨大。
这与每行需要多次比较的排序解决方案形成对比。基于排序的解决方案会比较慢,但会处理太大而无法放入内存的输出。
答案2
我将直接按第二个和第三个字段排序并通过awk
以保留最大值:
$ sort -k 3,3nr -k 5,5rn input | awk '!a[$3]++'
SMURF1 7 99143726 GACAGATTGG 74
CSNK1D 17 82251379 AATTTAGCCA 68
UBE2Z 17 48910880 CTAAGGATCC 48
AC003665.1 17 47813266 AGCAGGCGCA 83
RIOK3 18 23453502 GCAAGACTTT 69
这样做的优点是只对文件进行一次排序,并且不需要将整个文件保留在内存中。然而,我希望伊卡洛斯的 awk 方法更快,因为它只需要读取文件一次。