【问题标题】:Bash sort by number AND word length AND alphabeticallyBash 按数字和字长和字母顺序排序
【发布时间】:2016-04-27 17:11:06
【问题描述】:

我的数组中有这些字符串:

3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 som 11.11%
1 ok 11.11%
1 evo 11.11%

预期结果是:

3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 evo 11.11%
1 som 11.11%
1 ok 11.11%

它们按数字降序排列。

我也想按中间单词的长度对它们进行排序,但如果单词长度相同,请按字母顺序排列。

这些不是列。

我想把它分成两个数组,然后对它们进行排序,但是如何将它们连接在一起? 有人有想法吗?

【问题讨论】:

  • 您可以添加您的预期输出吗?您写“它们按数字降序排列,我想按单词长度排列它们”-它是哪一个?还是应该先按数字,然后按单词长度,然后按字母顺序?另外,我不明白“这些不是列”这句话。是否缺少逗号?
  • edit这个问题而不是在cmets中扩展它。
  • 您是否仅限于此使用 bash,或者您的系统上是否有其他标准shell 工具可用,例如awksort 等?
  • @ghoti 从对答案的评论来看,至少有sort 可用。
  • @BenjaminW。 - 是的,我明白了,只是试图鼓励 OP 在问题中更加明确。 :-P

标签: bash sorting numeric


【解决方案1】:

您不能使用 sort 按长度排序。让我们试试Schwartzian transform

awk '{print length($2), $0}' file | sort -k2,2nr -k1,1nr -k3,3 | cut -d" " -f2-

awk 命令接受1 something 11.11% 并输出9 1 something 11.11%
然后排序首先按数字的第二个字段排序,然后按数字的第一个字段,然后按词法的第三个字段。
然后 cut 删除第一个字段。

【讨论】:

  • 不错的链接;)
【解决方案2】:

这背后的想法和choroba's answer中使用的Schwartzian transform非常相似:我们添加一个排序字段(在本例中为第二列的长度),使用它进行排序,然后再次将其删除:

while read -r col1 word rest; do
    printf "%d\t%s %s %s\n" "${#word}" "$col1" "$word" "$rest"
done < infile | sort -k 2,2nr -k 1,1nr -k 3,3 | cut -f 2

这会导致

3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 evo 11.11%
1 som 11.11%
1 ok 11.11%

while循环之后,输出如下:

4   3 rere 33.33%
3   2 ena 22.22%
9   1 something 11.11%
3   1 som 11.11%
2   1 ok 11.11%
3   1 evo 11.11%

在第二列中有一个新列,其中包含字符串的长度。它是标签分隔的,以便之后更容易cutting。

对于sort,我们使用-k 参数指定用于排序的内容(sort 不关心字段是制表符还是空格分隔):2,2nr 仅使用第二个字段,数字和按降序排列; 1,1nr 也是如此,3,3 只是您的标准词汇排序。

现在的输出如下所示:

4   3 rere 33.33%
3   2 ena 22.22%
9   1 something 11.11%
3   1 evo 11.11%
3   1 som 11.11%
2   1 ok 11.11%

现在我们只需要去掉第一列,为此我们使用cut 并利用printf 引入的制表符分隔。

Bash while 循环非常慢,Perl 解决方案可能要快几个数量级。

【讨论】:

  • 谢谢老兄......它做到了......非常感谢你:D正是我需要的
【解决方案3】:

Perl 来救援!

perl -l -0777 -aF'\n' -ne '
    print for map join(" ", @$_),
              sort { $b->[0] <=> $a->[0] 
                     || length($a->[1]) <=> length($b->[1])
                     || $a->[1] cmp $b->[1] }
              map [ split ],
              @F;
    ' input-file
  • -n逐条读取输入记录
  • -0777 将整个文件设置为一条记录
  • -l 为打印添加换行符
  • -a 拆分输入
  • -F'\n' 告诉 -a 在换行符处拆分
  • 然后每行在空白处按split 分割,按数字 (&lt;=&gt;) 按第 0 列排序,或按第 1 列长度排序,或按字母顺序 (cmp) 按第一列排序

【讨论】:

  • 先生,谢谢您,但是...我什么都不懂:D 我不能使用“sort -k2 -k1”之类的命令先按第二列排序,然后再按第一个。如果您知道更简单的解决方案,不胜感激。
  • @darkneess96:我已经添加了一些解释。
猜你喜欢
  • 1970-01-01
  • 2021-03-27
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 2021-12-19
  • 1970-01-01
  • 2015-12-09
相关资源
最近更新 更多