输出得分最高的条目

输出得分最高的条目

我有一个如下文件。根据分数列,我想通过打印整行如下来输出每个科目得分最高的人。不需要特定的顺序,但主题列应该包含所有唯一的条目。

name subject score remarks
john   Math    67   satis
lewis  History 56   poor
sarah  Math    89   good
fiona  Geo     65   satis
george History 99   very good

所需输出:

name   subject score remarks
sarah  Math    89   good
george History 99   very good
fiona  Geo     65   satis

所有列均以制表符分隔,只有备注列具有空格分隔的单词。如果同一科目存在相同的分数,我想输出所有这些人。

答案1

就像是:

{
head -n 1 file.txt &&
tail -n+2 file.txt |
sort -t $'\t' -nrk 3 |
awk -F '\t' 's[$2] && s[$2] > $3 { next }{ s[$2] = $3 } 1'
} >outfile.txt
  • head -n1打印标题。

  • tail -n+2跳过标头和管道其余部分进行处理。

  • sort进行数字反向排序(从高到低)( -rn)。按输入的第 3 列 ( -k 3) 进行排序,并用制表符分隔(-t $'\t'如果名称或主题列中没有空格,则可以删除 - )。

  • awk只要没有看到主题,就打印行,或者等于最后一行。
    -F '\t'将字段分隔符设置为制表符。如果名称和主题列不包含空格,则可以删除。

    • s[$2] && s[$2] > $3 { next }下一个; ifs[subject]已设置且大于当前值(最高分)。
    • {s[$2] = 1}s[subject] = score
    • 1打印

如果您不介意最后一行的标题并且不需要考虑名字或者科目带空格(如:没有)——可以缩短为:

sort -nrk3 file.txt | awk ' s[$2] && s[$2] > $3{next}{s[$2]=$3}1'

答案2

awk 'BEGIN{ FS=OFS="\t" }
    NR==1              { print; next }
    max[$2]<$3 || NR==2{ max[$2]=$3; data[$2]=$0; next }
    max[$2]==$3        { data[$2]= data[$2] ORS $0 }

END{ for(x in data) print data[x] }' infile

  • BEGIN{ FS=OFS="\t" },设置制表\t符为F产量S输入的分隔符和输出F产量S输出的分隔符​​。
  • NR==1{ print; next },输出标题行。
  • max[$2]<$3 || NR==2{ max[$2]=$3; data[$2]=$0; next },更新并保留每个科目的最高分,并保留该高分科目的整行。
  • max[$2]==$3{ data[$2]= data[$2] ORS $0 },附加每个相同科目具有相同最高分数的记录。
  • END{ for(x in data) print data[x] },循环数据数组并打印最终结果。

答案3

使用 GNUsort进行排序并uniq只取每个主题的第一个:

sort -t '\t' -r -k 2 -k 3n scores.txt | uniq -f 1 -w 7

-k 2按主题(第二个字段)排序,-k 3n n并按分数(第三个字段)进行数字排序。该-r选项会颠倒排序顺序,因此得分最高的将排在第一位。

现在uniq删除两个主题,跳过第一个字段并-f 1仅比较 5,因此对于共享前 5 个字符(如HistoryA和 )的主题,这将失败HistoryB

至于使用uniq带有选项的命令-f,因此第一个字段不得包含空格,否则会产生错误的输出,因为该字段是一系列空格(通常是空格和/或制表符),然后是非空白字符。某些特定版本仅在 Debian 中uniq可以-t选择指定字段分隔符,但现在出于兼容性原因删除了。

答案4

awk 'NR==FNR {if ($3>max[$2]) max[$2]=$3; next} FNR==1||$3==max[$2]' file file

对输入文件进行两次遍历。第一遍记录最高分,第二遍打印行。假设分数大于零。

相关内容