您如何在最接近$VariableNumber
的数字列中找到5个数字?
例如,如果$VariableNumber
= 30则:
示例输入文件:
50
100
70
40
20
10
65
41
92
示例输出:
20
40
41
10
50
有一个答案,有人在之前发布的其他地方找到了特定行中特定列中与给定值最接近的数字匹配,如下所示:
awk -v col_num="3" -v value="$Number" '
func abs(x) { return (x<0) ? -x : x }
{
distance = abs($col_num - value)
}
NR==1 || distance<shortest_distance {
shortest_distance = distance
nearest_value = $col_num
}
END {
print nearest_value
}
'
但我无法适应它
我只是按距离n对条目进行排序,然后选择第一个:
awk -v n=30 '
function abs(x) {return x < 0 ? -x : x}
{print abs($0 - n) "\t" $0}' < file |
sort -n |
head -n 5 |
cut -f 2-
像往常一样,Stéphane’s answer非常好;简单明了。但是,如果你真的想完全在awk
中完成它,并且你有GNU awk
(a.k.a。gawk
),你可以这样做:
awk -v t="$VariableNumber" '
{
d = $1 - t
if (d < 0) d = -d
e = d "#" $1
if (NR <= 5) {
a[NR] = e
} else {
a[5+1] = e
asort(a, a, "@val_num_asc")
delete a[5+1]
}
}
END {
print "---"
if (NR <= 5) asort(a, a, "@val_num_asc")
for (i in a) { gsub(".*#", "", a[i]); print a[i]; }
}
'
对于每个输入值,这将计算d
作为该值与目标值之间的绝对差值t
(在命令行上设置为$VariableNumber
的值,根据您的示例,可能为30)。然后它构造一个数组条目e
,由差异组成,与#
和原始数字连接。然后将此数组条目添加到数组a
。
前五个输入值简单地放入数组元素1到5中。
之后,通过将数字放入元素6,将每个数字附加到数组中。然后对数组进行排序。由于数组条目以差值开头,因此接近目标的数字(差值为低)将被排序到数组的开头,而远离目标的数字将被排序到数据的末尾。阵列。 (指定"@val_num_asc"
将值排序为数字而不是字符串。如果没有这个,10
和20
的差异将排在3
和4
之下。)然后删除第6个元素(距离目标最远的元素)。
最后(在达到数据的结尾时),我们
#
并用(.*#
)替换来消除差异和gsub
。然后打印原始值。显然,如果要查看第一列的其他列,可以在脚本中更改$1
的所有匹配项。 (您在问题中显示的脚本演示了如何在运行时指定列号。)并且,如果您想要除最接近的五个之外的其他数字,只需更改5
的所有外观。 (我本可以在第9行和第11行中提到a[6]
;我写了a[5+1]
来促进简单的参数化。)
另一个,对于所有的awks(用gawk,mawk,Debian的原始awk和Busybox awk测试):
$ awk -v v=30 -v n=5 ' # v is the central value,
function abs(d) { # n is the number of wanted values
return (d<0?-d:d) # d is distance, c array index, va value array
} # da distance array, max is greatest of smallest
((d=abs(v-$1))<max) && c==n { # if we find distance < max of top n smallest
da[maxc]=d # replace max in distance array
va[maxc]=$1 # and in value array
max=0 # set max to min to find new max distance
for(ct in da)
if(da[ct]>max) { # find the new max in the top n smallest
max=da[ct]
maxc=ct
}
if(max==0) # if max is 0, all are 0s so might as well exit
exit
next
}
c<n { # we need n first distances
da[++c]=d # fill distance array with them
va[c]=$1 # related values to value array
if(d>max) { # look for max
max=d
maxc=c
}
}
END { # in the end or exit
for(c in va) # get all values in value array
print va[c] # and output them
}' file
输出(无特定顺序,与数组实现相关):
50
10
41
40
20
执行时间是线性的,最坏的情况是值数组的大小乘以记录计数,所以仍然是线性的(对吗?:)。