[英]Compare values of each records in field 1 to find min and max values AWK
我是文字预处理和AWK语言的新手。
我试图遍历给定field(field1)中的每个记录,找到值的最大值和最小值并将其存储在变量中。
算法:
1)设置最小值= 0和最大值= 0
2)遍历$ 1(字段1)
3)比较字段1的FNR并设置最大值和最小值
4)最后打印最大和最小
这是我尝试的:
BEGIN{max = 0; min = 0; NF = 58}
{
for(i = 0; i < NF-57; i++)
{
for(j =0; j < NR; j++)
{
min = (min < $j) ? min : $j
max = (max > $j) ? max : $j
}
}
}
END{print max, min}
#Dataset
f1 f2 f3 f4 .... f58
0.3 3.3 0.5 3.6
0.9 4.7 2.5 1.6
0.2 2.7 6.3 9.3
0.5 3.6 0.9 2.7
0.7 1.6 8.9 4.7
此处,f1,f2,..,f58是数据集中的字段或列。
我需要遍历第一栏(f1)并找到Min-Max。
所需的输出:最小值= 0.2最大值= 0.9
结果是:Min =”(我没有得到任何结果)Max = 9.3(我得到了所有字段的最大值,而不是field1)
这是出于学习目的,因此我要求一列,以便我可以自己尝试多列
这些是我所拥有的:
因为只有四个字段,所以此for循环仅循环4次。 for循环内的代码是否会对每个记录执行5次?
for(i = 0; i < NF; i++)
{
if (min[i]=="") min[i]=$i
if (max[i]=="") max[i]=$i
if ($i<min[i]) min[i]=$i
if ($i>max[i]) max[i]=$i
}
END
{
OFS="\t";
print "min","max";
#If I am not wrong, I saved the data in an array and I guess this would be the right way to print all min and max?
for(i=0; i < NF; i++;)
{
print min[i], max[i]
}
}
这是一个可行的解决方案,实际上比您正在做的事情容易得多:
/^-?[0-9]*(\\.[0-9]*)?$/
检查$1
确实是有效数字,否则将其丢弃。
sort -n | awk '$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {a[c++]=$1} END {OFS="\t"; print "min","max";print a[0],a[c-1]}'
如果不使用此参数,则需要初始化min和max,例如,使用第一个值:
awk '$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {if (min=="") min=$1; if (max=="") max=$1; if ($1<min) min=$1; if ($1>max) max=$1} END {OFS="\t"; print "min","max";print min, max}'
可读版本:
sort -n | awk '
$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {
a[c++]=$1
}
END {
OFS="\t"
print "min","max"
print a[0],a[c-1]
}'
和
awk '
$1 ~ /^-?[0-9]*(\.[0-9]*)?$/ {
if (min=="") min=$1
if (max=="") max=$1
if ($1<min) min=$1
if ($1>max) max=$1
}
END {
OFS="\t"
print "min","max"
print min, max
}'
在您的输入上是输出:
min max
0.2 0.9
编辑(回复评论,需要更多有关awk
如何工作的信息) :
Awk遍历lines
(命名为records
),并且每一行都有可用的列(命名为fields
)。 每个awk
迭代都读取一行,并提供NR
和NF
变量等。 在您的情况下,您仅对第一列感兴趣,因此仅使用$1
作为第一列field
。 对于$1
与/^-?[0-9]*(\\.[0-9]*)?$/
匹配的每条record
,它是一个正负整数或浮点数的正则表达式,我们将值存储在阵列a
(在第一版本)或设置min
/ max
,如果需要(在第二版本)的变量。
这是条件$1 ~ /^-?[0-9]*(\\.[0-9]*)?$/
- $1 ~ /^-?[0-9]*(\\.[0-9]*)?$/
:
$1 ~
表示我们正在检查第一个字段$1
与斜杠之间的正则表达式匹配 ^
表示我们从$1
字段的开头开始匹配 -?
表示可选的minus sign
[0-9]*
是任意位数(包括零,因此可以匹配.1
或-.1
) ()?
表示可以存在或不存在的可选块 \\.[0-9]*
如果存在该可选块,则应以dot
并包含零个或多个数字(因此-.
或.
可以匹配!如果输入不确定,请使用正则表达式) $
表示匹配,直到$1
字段中的最后一个字符 如果要遍历fields
,则必须使用从1
到NF
(包括)的for循环,如下所示:
echo "1 2 3 4" | awk '{for (i=1; i<=NF; i++) {if (min=="") min=$(i); if (max=="") max=$(i); if ($(i)<min) min=$(i); if ($(i)>max) max=$(i)}} END {OFS="\t"; print "min","max";print min, max}'
(请注意,为简单起见,我没有在此处检查输入)
哪个输出:
min max
1 4
如果您有更多行作为输入, awk
还将在读取第一条record
(使用此输入的示例)后对其进行处理:
1 2 3 4
5 6 7 8
输出:
min max
1 8
为了防止这种情况,并且仅在第一行上起作用,可以添加类似NR == 1
的条件以仅处理第一行,或者在for
循环之后添加exit
语句以停止处理第一行之后的输入。
如果仅查找第1列,则可以尝试以下操作:
awk '/^[[:digit:]].*/{if($1<min||!min){min=$1};if($1>max){max=$1}}END{print min,max}' dataset
脚本会查找以digit开头的行,并设置之前未找到的最小值或最大值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.