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



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

以制表符分隔的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

如果您查看"品牌"列,您可以看到讴歌和本田等名称重复,但"型号"和"总计"列有所不同。假设 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] = $4;
}
END {
PROCINFO["sorted_in"] = "@val_str_desc"
for(i = 1; i < FN-1; i++) {
print a[i];
}
}

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

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

排序是sort的工作,headtail可以用来隔离标题行,awk可以用来每Make最多保留3个,并对第一列重新编号:

$ head -n1 data.tsv; tail -n+2 data.tsv | sort -t$'t' -k4,4 -k6,6rn |
awk -F't' -vOFS='t' '$4==p {n+=1} $4!=p {n=1;p=$4} {$1=++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个最大的Total(112, 106, 102用于Honda,而不是112, 102, 92)。

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

$ awk -F't' -vOFS='t' 'NR==1 {print; next} {l[$4][$6][$0]}
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]]) {$0 = s; $1 = ++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[$4][$6][++numRows[$4,$6]] = $0
}
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 辆讴歌中,总共有 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 个讴歌中的 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 )测试移动到外部循环或根据需要处理它。

最新更新