我的数据看起来像这样: A学校和B学校每个班级的最高和最低中期成绩(未显示班级)
#school highest lowest
schoolA 99 53
schoolA 95 66
schoolA 88 48
schoolB 94 55
schoolB 91 36
我想像这样合并它:
schoolA 99 48
schoolB 94 36
显示每所学校的最大和最小。 我已经尝试过类似的东西:
awk '
BEGIN{getline;min=$3;max=$2}
{($3<min)?min=$3:"";($2>max)?max=$2:""}
END{OFS="\t";print $1,max,min}
'
它奏效了;但是,有时它会自动在最小值处加一个点(第三列)
有人可以教我如何正确执行此操作,并解释一下上面的代码是什么意思吗? (尤其是“ getline”)此代码可以按第一列(学校)合并行吗?
答案 0 :(得分:3)
如果datamash没问题:
$ datamash -W -g1 max 2 min 3 < ip.txt
schoolA 99 48
schoolB 94 36
-W
使用空格作为分隔符-g1
按第一字段分组max 2 min 3
最多第二个字段,最少三个字段--header-in
选项将其忽略答案 1 :(得分:0)
首先,我认为您的(condition)?var=one:two
不正确。例如:
awk 'BEGIN{(3>5)?a=1:2;print a}'
不输出任何内容。应该写成:
$ awk 'BEGIN{a=(3>5)?1:2;print a}'
2
getline
。school
,因此您的代码将在所有学校值中找到最小值/最大值。这不是你想要的。对于您的问题,您可以这样写:
awk -v OFS='\t' '$1 in min{min[$1]=$3<min[$1]?$3:min[$1]
max[$1]=$2>max[$1]?$2:max[$1]
next } {min[$1]=$3;max[$1]=$2}
END{for(x in min)print x, max[x], min[x]}' file
答案 2 :(得分:0)
使用POSIX awk,您可以执行以下操作:
awk ' BEGIN{fmt="%-15s%-10s%-10s\n"; printf fmt,"School","max","min"}
!($1 in sch) {idx[++i]=$1; sch[$1]; arr[$1,"min"]=100}
$2>arr[$1,"max"]{arr[$1,"max"]=$2}
$3<arr[$1,"min"]{arr[$1,"min"]=$3}
END{for (e=1;e<=length(idx);e++) printf fmt,idx[e],arr[idx[e],"max"],arr[idx[e],"min"]}' file
School max min
schoolA 99 48
schoolB 94 36
按照书面规定,这将维护印刷学校的文件顺序。如果您不关心输出顺序,则编写起来会更简单。
不清楚您的文件是否带有标题。
如果确实有标题,则将printf fmt,"School","max","min"
替换为FNR==1{printf fmt,$1,$2,$3}
以打印标题。 (如果要跳过标题,则为FNR==1{next}
。)
答案 3 :(得分:0)
getline
获取下一个输入行。不过,从BEGIN
块开始执行此操作并不算什么,因为Awk仍会读取每一行。我会改为:
NR==1{min=$3;max=$2;next}
确保在脚本启动时将max
和min
初始化为第一行的值。
($3<min?min=$3:"")
和$2
和max
的相应语句非常晦涩。构造x ? y : z
被称为三元运算符,并且是if (x) y; else z
的简写,因此其计算结果为
if($3<min)
min=$3
else
""
在这种情况下,""
基本上就像一条注释,即一种明确表示“不做任何事情”的方式。
您当前的脚本获取总的最大值和最小值。您显然希望分别获取每个键的最大值和最小值。假设每个学校的所有值都相邻,
NR>1 && $1!=prev { print prev, max, min }
NR==1 || $1!=prev { prev=$1; max=$2; min=$3 }
$2>max { max=$2 }
$3<min { min=$3 }
END { print prev, max, min }
如果对输入进行了排序,至少足以在相邻行上全部提及一个keye,Awk可以处理更大的输入文件,因为它不需要将所有键都保留在内存中。您的示例文件似乎具有此属性,因此,如果它具有代表性,则应该可以使用。如果不是,请使用sort file | awk
(在丢弃任何标题行(如果存在)之后)。
如果输入文件具有标题,但已经进行了排序,则在顶部添加NR==1 { next }
以跳过它,然后将其他NR
提及的内容调整为2而不是1。