比较字段 1 中每条记录的值以查找最小值和最大值 AWK
Compare values of each records in field 1 to find min and max values AWK
我是文本预处理和 AWK 语言的新手。
我正在尝试遍历给定字段 (field1) 中的每条记录并找到值的最大值和最小值并将其存储在变量中。
算法:
1) 设置最小值 = 0 和最大值 = 0
2) 遍历 $1(字段 1)
3) 比较字段1的FNR并设置Max和Min
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]
}
}
如果您只想查看第 1 列,您可以试试这个:
awk '/^[[:digit:]].*/{if(<min||!min){min=};if(>max){max=}}END{print min,max}' dataset
脚本查找以数字开头的行,如果之前没有找到,则设置最小值或最大值。
这是一个可行的解决方案,它确实比您正在做的要容易得多:
/^-?[0-9]*(\.[0-9]*)?$/
检查 </code> 确实是一个有效数字,否则将被丢弃。</p>
<pre><code>sort -n | awk ' ~ /^-?[0-9]*(\.[0-9]*)?$/ {a[c++]=} END {OFS="\t"; print "min","max";print a[0],a[c-1]}'
如果你不使用这个,那么需要初始化min和max,例如第一个值:
awk ' ~ /^-?[0-9]*(\.[0-9]*)?$/ {if (min=="") min=; if (max=="") max=; if (<min) min=; if (>max) max=} END {OFS="\t"; print "min","max";print min, max}'
可读版本:
sort -n | awk '
~ /^-?[0-9]*(\.[0-9]*)?$/ {
a[c++]=
}
END {
OFS="\t"
print "min","max"
print a[0],a[c-1]
}'
和
awk '
~ /^-?[0-9]*(\.[0-9]*)?$/ {
if (min=="") min=
if (max=="") max=
if (<min) min=
if (>max) max=
}
END {
OFS="\t"
print "min","max"
print min, max
}'
在你的输入中,输出是:
min max
0.2 0.9
编辑(回复需要更多有关 awk
工作原理的信息的评论):
Awk 循环遍历 lines
(名为 records
)并且对于每一行您都有可用的列(名为 fields
)。每个 awk
迭代读取一行并提供 NR
和 NF
变量等。在您的情况下,您只对第一列感兴趣,因此您将只使用 </code>,即第一列 <code>field
。对于每个 record
其中 </code> 匹配 <code>/^-?[0-9]*(\.[0-9]*)?$/
这是一个匹配正负整数或浮点数的正则表达式,我们要么将值存储在数组 a
中(在第一个版本)或根据需要设置 min
/max
变量(在第二个版本中)。
条件 ~ /^-?[0-9]*(\.[0-9]*)?$/
的解释如下:
~
表示我们正在检查第一个字段 </code> 是否与斜杠之间的正则表达式匹配 </li>
<li><code>^
表示我们从</code>字段开始匹配</li>
<li><code>-?
表示可选的 minus sign
[0-9]*
为任意位数(包括零,所以可以匹配.1
或-.1
)
()?
表示可选块,可以存在也可以不存在
\.[0-9]*
如果该可选块存在,它应该以 dot
开头并包含零个或多个数字(因此可以匹配 -.
或 .
!如果您有不确定的输入,请调整正则表达式)
$
表示我们一直匹配到 </code> 字段的最后一个字符 </li>
</ul>
<p>如果你想遍历 <code>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
语句在第一行之后停止处理输入。
我是文本预处理和 AWK 语言的新手。
我正在尝试遍历给定字段 (field1) 中的每条记录并找到值的最大值和最小值并将其存储在变量中。
算法:
1) 设置最小值 = 0 和最大值 = 0
2) 遍历 $1(字段 1)
3) 比较字段1的FNR并设置Max和Min
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]
}
}
如果您只想查看第 1 列,您可以试试这个:
awk '/^[[:digit:]].*/{if(<min||!min){min=};if(>max){max=}}END{print min,max}' dataset
脚本查找以数字开头的行,如果之前没有找到,则设置最小值或最大值。
这是一个可行的解决方案,它确实比您正在做的要容易得多:
/^-?[0-9]*(\.[0-9]*)?$/
检查 </code> 确实是一个有效数字,否则将被丢弃。</p>
<pre><code>sort -n | awk ' ~ /^-?[0-9]*(\.[0-9]*)?$/ {a[c++]=} END {OFS="\t"; print "min","max";print a[0],a[c-1]}'
如果你不使用这个,那么需要初始化min和max,例如第一个值:
awk ' ~ /^-?[0-9]*(\.[0-9]*)?$/ {if (min=="") min=; if (max=="") max=; if (<min) min=; if (>max) max=} END {OFS="\t"; print "min","max";print min, max}'
可读版本:
sort -n | awk '
~ /^-?[0-9]*(\.[0-9]*)?$/ {
a[c++]=
}
END {
OFS="\t"
print "min","max"
print a[0],a[c-1]
}'
和
awk '
~ /^-?[0-9]*(\.[0-9]*)?$/ {
if (min=="") min=
if (max=="") max=
if (<min) min=
if (>max) max=
}
END {
OFS="\t"
print "min","max"
print min, max
}'
在你的输入中,输出是:
min max
0.2 0.9
编辑(回复需要更多有关 awk
工作原理的信息的评论):
Awk 循环遍历 lines
(名为 records
)并且对于每一行您都有可用的列(名为 fields
)。每个 awk
迭代读取一行并提供 NR
和 NF
变量等。在您的情况下,您只对第一列感兴趣,因此您将只使用 </code>,即第一列 <code>field
。对于每个 record
其中 </code> 匹配 <code>/^-?[0-9]*(\.[0-9]*)?$/
这是一个匹配正负整数或浮点数的正则表达式,我们要么将值存储在数组 a
中(在第一个版本)或根据需要设置 min
/max
变量(在第二个版本中)。
条件 ~ /^-?[0-9]*(\.[0-9]*)?$/
的解释如下:
~
表示我们正在检查第一个字段</code> 是否与斜杠之间的正则表达式匹配 </li> <li><code>^
表示我们从</code>字段开始匹配</li> <li><code>-?
表示可选的minus sign
[0-9]*
为任意位数(包括零,所以可以匹配.1
或-.1
)()?
表示可选块,可以存在也可以不存在\.[0-9]*
如果该可选块存在,它应该以dot
开头并包含零个或多个数字(因此可以匹配-.
或.
!如果您有不确定的输入,请调整正则表达式)$
表示我们一直匹配到</code> 字段的最后一个字符 </li> </ul> <p>如果你想遍历 <code>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
语句在第一行之后停止处理输入。