如果我有一组数据具有重复的名称值,但每个重复值具有不同的变化,如何按每个重复值的顶部进行排序?希望这是有道理的,但我希望在下面进一步说明我的意思。
以制表符分隔的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
的工作,head
和tail
可以用来隔离标题行,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
按字母顺序排序(Audi
在Acura
之后,而不是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 )
测试移动到外部循环或根据需要处理它。