如何按字母顺序然后按列数字对 csv 数据进行排序?

How can I sort csv data alphabetically then numerically by column?

如果我有一组具有重复名称值但每个重复值有不同变化的数据,我如何按每个重复值的顶部排序?希望这是有道理的,但我希望在下面进一步证明我的意思。

以制表符分隔的csv文件中的这组数据为例

Ranking  ID     Year  Make        Model     Total
1        128    2010  Infiniti    G37       128
2        124    2015  Jeep        Wrangler  124
3        15     014   Audi        S4        120
4        113    2012  Acura       Tsx       sportwagon  116
5        83     2014  Honda       Accord    112
6        112    2008  Acura       TL        110
7        65     2009  Honda       Fit       106
8        91     2010  Mitsu       Lancer    102
9        50     2015  Acura       TLX       102
10       31     2007  Honda       Fit       102
11       216    2007  Chrystler   300       96
12       126    2010  Volkswagen  Eos       92
13       13     2016  Honda       Civic     1.5t        92

如果查看“制造商”列,您会看到 Acura 和 Honda 等名称重复出现,但在“型号”和“总计”列中有所不同。假设 csv 文件中有 200 行左右。如何对文件进行排序,以便项目按品牌分组,每个品牌显示的“总计”列下只有三个价值最高的项目?

预期输出低于

Ranking   ID      Year    Make     Model           Total
1         113     2012    Acura    Tsx sportwagon  116
2         112     2008    Acura    TL              110
3         50      2015    Acura    TLX             106
4         83      2014    Honda    Accord          112
5         31      2007    Honda    Fit             102
6         13      2016    Honda    Civic 1.5t      92
...

到目前为止,这是我的 awk 代码,我什至无法通过这部分来尝试按总列对品牌进行分组

BEGIN {
        FS = OFS = "\t";
}
FNR == 1 {
        print;
        next;
}
FNR > 1 {
        a[NR] = ;
}
END {
        PROCINFO["sorted_in"] = "@val_str_desc"
        for(i = 1; i < FN-1; i++) {
                print a[i];
        }
}

目前,我的代码读取文本文件,打印 headers(列标题)然后停在那里,它不会继续按字母顺序打印其余数据。有什么想法吗?

以下假定 bash(如果您不使用 bash 将 $'\t' 替换为带引号的实际制表符)和 GNU coreutils。它还假定您要先按 Make 列的字母顺序排序,然后按 Total 的数字降序排序,最后最多保留每个 Make 条目的前 3 个。

排序是sort的工作,headtail可以用来隔离header行,awk可以用来每个 Make 最多保留 3 个,并且 re-number 第一列:

$ head -n1 data.tsv; tail -n+2 data.tsv | sort -t$'\t' -k4,4 -k6,6rn |
  awk -F'\t' -vOFS='\t' '==p {n+=1} !=p {n=1;p=} {=++r} n<=3'
Ranking  ID   Year  Make        Model           Total
1        113  2012  Acura       Tsx sportwagon  116
2        112  2008  Acura       TL              110
3        50   2015  Acura       TLX             102
4        15   014   Audi        S4              120
5        216  2007  Chrystler   300             96
6        83   2014  Honda       Accord          112
7        65   2009  Honda       Fit             106
8        31   2007  Honda       Fit             102
10       128  2010  Infiniti    G37             128
11       124  2015  Jeep        Wrangler        124
12       91   2010  Mitsu       Lancer          102
13       126  2010  Volkswagen  Eos             92

请注意,这与您的预期输出不同:Make 按字母顺序排序(AudiAcura 之后,而不是 Honda)并且只有 3保留最大的 Total112, 106, 102 用于 Honda,而不是 112, 102, 92)。

如果您使用 GNU awk,并且您的输入文件足够小以适合内存,您也可以只用 awk 完成所有这些,这要归功于它的多维数组和它的 asorti 函数,根据索引对数组进行排序:

$ awk -F'\t' -vOFS='\t' 'NR==1 {print; next} {l[][][[=11=]]}
  END {
    PROCINFO["sorted_in"] = "@ind_str_asc"
    for(m in l) {
      n = asorti(l[m], t, "@ind_num_desc"); n = (n>3) ? 3 : n
      for(i=1; i<=n; i++) for(s in l[m][t[i]]) {[=11=] = s;  = ++r; print}
    }
  }' data.tsv
Ranking  ID   Year  Make        Model           Total
1        113  2012  Acura       Tsx sportwagon  116
2        112  2008  Acura       TL              110
3        50   2015  Acura       TLX             102
4        15   014   Audi        S4              120
5        216  2007  Chrystler   300             96
6        83   2014  Honda       Accord          112
7        65   2009  Honda       Fit             106
8        31   2007  Honda       Fit             102
9        128  2010  Infiniti    G37             128
10       124  2015  Jeep        Wrangler        124
11       91   2010  Mitsu       Lancer          102
12       126  2010  Volkswagen  Eos             92

对数组的数组使用 GNU awk 和 sorted_in:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == 1 {
    print
    next
}
{
    rows[][][++numRows[,]] = [=10=]
}
END {
    PROCINFO["sorted_in"] = "@ind_str_asc"
    for ( make in rows ) {
        PROCINFO["sorted_in"] = "@ind_num_desc"
        cnt = 0
        for ( total in rows[make] ) {
            for ( rowNr=1; rowNr<=numRows[make,total]; rowNr++ ) {
                if ( ++cnt <= 3 ) {
                    row = rows[make][total][rowNr]
                    print row, cnt
                }
            }
        }
    }
}

$ awk -f tst.awk file
Ranking ID      Year    Make    Model   Total
4       113     2012    Acura   Tsx sportwagon  116     1
6       112     2008    Acura   TL      110     2
9       50      2015    Acura   TLX     102     3
3       15      014     Audi    S4      120     1
11      216     2007    Chrystler       300     96      1
5       83      2014    Honda   Accord  112     1
7       65      2009    Honda   Fit     106     2
10      31      2007    Honda   Fit     102     3
1       128     2010    Infiniti        G37     128     1
2       124     2015    Jeep    Wrangler        124     1
8       91      2010    Mitsu   Lancer  102     1
12      126     2010    Volkswagen      Eos     92      1

上面的代码将处理 1 个品牌的多辆汽车总数相同的情况,方法是始终只打印该品牌的前 3 行,例如鉴于此输入,其中 4 个 Acuras 总共有 116 个:

$ cat file
Ranking ID      Year    Make    Model   Total
1       128     2010    Infiniti        G37     128
2       124     2015    Jeep    Wrangler        124
3       15      014     Audi    S4      120
4       113     2012    Acura   Tsx sportwagon  116
4       113     2012    Acura   Foo     116
4       113     2012    Acura   Bar     116
4       113     2012    Acura   Other   116
5       83      2014    Honda   Accord  112
6       112     2008    Acura   TL      110
7       65      2009    Honda   Fit     106
8       91      2010    Mitsu   Lancer  102
9       50      2015    Acura   TLX     102
10      31      2007    Honda   Fit     102
11      216     2007    Chrystler       300     96
12      126     2010    Volkswagen      Eos     92
13      13      2016    Honda   Civic 1.5t      92

这是仅显示 4 116 辆 Acuras 中的 3 辆的输出:

$ awk -f tst.awk file
Ranking ID      Year    Make    Model   Total
4       113     2012    Acura   Tsx sportwagon  116     1
4       113     2012    Acura   Foo     116     2
4       113     2012    Acura   Bar     116     3
3       15      014     Audi    S4      120     1
11      216     2007    Chrystler       300     96      1
5       83      2014    Honda   Accord  112     1
7       65      2009    Honda   Fit     106     2
10      31      2007    Honda   Fit     102     3
1       128     2010    Infiniti        G37     128     1
2       124     2015    Jeep    Wrangler        124     1
8       91      2010    Mitsu   Lancer  102     1
12      126     2010    Volkswagen      Eos     92      1

如果这不是您想要的,则将 if ( ++cnt <= 3 ) 测试移至外循环或按您希望的方式处理它。