当排序不知道排序顺序时,GNU排序稳定排序


18

我有一个两栏的文件;该文件已经按照我想要的方式在第1列上进行了排序。我想对每个列1类别中的列2进行排序。但是,sort不了解第1列的排序顺序。

正常的方式(来自栈上类似的问题)是这样的:

sort --stable -k1,1 -k2,2n

但是我无法在k1上指定排序,因为它是任意的。

输入示例:

C 2
C 1
A 2
A 1
B 2 
B 1

并输出:

C 1
C 2
A 1
A 2
B 1 
B 2

Answers:


20

您可以使用awk为每个块开始新的排序:

% awk -v cmd="sort -k2,2" '$1 != prev {close(cmd); prev=$1} {print | cmd}' foo
C 1
C 2
A 1
A 2
B 1
B 2
  • $1 != prev {close(cmd); prev=$1} -当保存的值不同时,我们有一个新的块,因此我们关闭任何先前开始的块 sort
  • {print | "sort -k2,2"}'将输出通过管道传输到sort,如果尚未运行,则将其启动(awk可以跟踪其启动的命令)

2
awk确实令人难以置信。我非常喜欢我的预期,这是awk decorate-sort-unecorate!
埃文·本恩

我试图比较此答案与其他答案的性能,不知道为什么要使用更多资源...有什么想法吗?gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Evan Benn

您平均进行了几次跑步?
穆鲁

我没有进行平均,但是在重复和研究时看到的是一致的运行时。
埃文·本

这是与我要调查的文件类似的文件:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Evan Benn,

12

您可以使用Schwartzian变换(这基本上是您在评论中提到的decorate-sort-unecorate方法,但由于使用了单个调用而不是多个调用,因此可能比muru的 好的答案更有效sort)-使用awk添加前缀列在第一列中随着值的变化而增加,按前缀列排序,然后在“第二”列中排序(3由于存在前缀列,其序号位置已临时移至该列),最后摆脱前缀列

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-

我很惊讶,但是您是正确的,这比其他答案要快!1亿行文件需要3分钟,而2分钟需要2分钟(〜30 uniq第一列)。
埃文·本

1
无需保留第一列中唯一键的数组。我认为将当前行的第一列与前一行进行比较就足够了。
库萨兰达

awk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(未经测试)的东西。
库萨兰达
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.