繁体   English   中英

比较字段1中每个记录的值以找到最小值和最大值AWK

[英]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迭代都读取一行,并提供NRNF变量等。 在您的情况下,您仅对第一列感兴趣,因此仅使用$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 ,则必须使用从1NF (包括)的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM