根据第二个字段进行排序,然后对具有相同第一列的行重新排序,但仍保留每个组的第二个字段的顺序

根据第二个字段进行排序,然后对具有相同第一列的行重新排序,但仍保留每个组的第二个字段的顺序

我想对文件进行排序。

输入:

I1, -2   
I2, -6  
I2, -9  
I1, -8  
I1, -1  
I3, -7  
I2, -4  
I3, -4  

输出 :

I2, -9  
I2, -6  
I2, -4  
I1, -8  
I1, -2  
I1, -1  
I3, -7  
I3, -4

如何得到下面的输出?

答案1

一个肮脏的解决方案是:

<infile sort -t, -rk2,2 \
|awk -F, '{ seen[$1]= (seen[$1]==""? "\0":seen[$1] ORS) $0 }
 END{ for (x in seen) print seen[x] }' \
|sort -z -t, -rk2,2 \
|tr -d '\0'

分解:

  • <infile sort -t, -rk2,2
    这会对r输入文件进行相反的排序infile第二个字段(逗号是分隔符)作为key 字段。

  • awk代码只是对具有相同第一列的记录重新排序;我们将每组分开无效的特点\0

  • sort -z -t, -rk2,2
    -z这个反向排序对第二个字段和逗号分隔字段上的 这些块(用空字符分隔;我们用 告诉排序命令)进行排序。请在运行此步骤之前查看以下输出并添加cat -A您将看到:

    ^@I1, -8$
    I1, -2$
    I1, -1$
    ^@I2, -9$
    I2, -6$
    I2, -4$
    ^@I3, -7$
    I3, -4$
    

    ^@字符代表空字符,sort -z上面的输入看到的是这样的(我这样做是为了人类可读和更好的理解)

    ^@I1, -8$      I1, -2$      I1, -1$
    ^@I2, -9$      I2, -6$      I2, -4$
    ^@I3, -7$      I3, -4$
    

    你明白了,上面的排序命令看到第二个字段如下

     -8$      I1
     -9$      I2
     -7$      I3
    

    ...并对这些进行反向排序,结果更改为以下内容:

    ^@I2, -9$      I2, -6$      I2, -4$
    ^@I1, -8$      I1, -2$      I1, -1$
    ^@I3, -7$      I3, -4$
    

    ...如果我们返回结构,我们实际上有这个:

    ^@I2, -9$
    I2, -6$
    I2, -4$
    ^@I1, -8$
    I1, -2$
    I1, -1$
    ^@I3, -7$
    I3, -4$
    
  • tr -d '\0'
    这会从结果中删除添加的空字符,最终输出为:

    I2, -9
    I2, -6
    I2, -4
    I1, -8
    I1, -2
    I1, -1
    I3, -7
    I3, -4
    

答案2

使用 GNU awk

gawk '
  grp[$1] == "" || $2 < grp[$1] { grp[$1] = $2 }
  { val[$1][$2] }
  END {
    PROCINFO["sorted_in"] = "@val_num_asc"
    for (i in grp) {
      PROCINFO["sorted_in"] = "@ind_num_asc"
      for (j in val[i]) print i,j
    }
  }' ./file

这个想法是:

  • grp为数组中第 1 列的每个不同值存储第 2 列的最小值
  • 将每一行存储在二维数组中val,以便方便地检索第 1 列的每个不同值的第 2 列的值(您还可以使用val[$1][$2] = $0print val[i][j]来保留数据的原始间距)
  • 用于根据其元素的值PROCINFO["sorted_in"]遍历数组,并根据其索引的值遍历(单维)数组(始终按升序排序)。 请注意,如果您想要更改与第 2 列共享相同最小值的第 1 列值的排序顺序(例如,如果您添加到样本数据并希望在输出之前排序) ,您可能需要定义自己的排序函数)。grpval[i]
    I4, -9I4I2

一种便携式替代方案,基于施瓦茨变换, 或许:

sort -k2,2n ./file |
  awk '
    grp[$1] == "" { grp[$1] = $2 }
    { print grp[$1] "," $0 }' |
  sort -t, -k 1,1n -k 2,2 -k 3,3n |
  cut -d, -f2-

其中,第 2 列的“每组”(即相对于第 1 列的值)最小值被添加到每行前面,允许基于每组最小值 ( -9-8-7)、列的值进行后续排序1(以保持按其分组的行),并且第 2 列的值
awk提供有排序的数据,以使脚本更简单:对于每行,当满足该行时,每组的最小值已经知道,无需存储某些结构中的行并将它们打印在一个END块中(或处理文件两次)。

相关内容