尝试这个:
awk -v c=2 -v t=35 'NR==1{d=$c-t;d=d<0?-d:d;v=$c;next}{m=$c-t;m=m<0?-m:m}m<d{d=m;v=$c}END{print v}' file
和可以是动态值-v c=2
。-v t=35
它们是列 idx ( c
) 和您的目标值 ( t
)。在上面的行中,参数是第 2 列和目标 25。它们可以是 shell 变量。
基于给定输入数据的上述行的输出是:
kent$ awk -v c=2 -v t=35 'NR==1{d=$c-t;d=d<0?-d:d;v=$c;next}{m=$c-t;m=m<0?-m:m}m<d{d=m;v=$c}END{print v}' f
34.988528
kent$ awk -v c=1 -v t=11.6 'NR==1{d=$c-t;d=d<0?-d:d;v=$c;next}{m=$c-t;m=m<0?-m:m}m<d{d=m;v=$c}END{print v}' f
11.700000
编辑
如果有两个数字与目标值等距,则应输出较大的值
上面的代码没有检查这个要求....下面的代码应该可以工作:
awk -v c=1 -v t=11.6 '{a[NR]=$c}END{
asort(a);d=a[NR]-t;d=d<0?-d:d;v = a[NR]
for(i=NR-1;i>=1;i--){
m=a[i]-t;m=m<0?-m:m
if(m<d){
d=m;v=a[i]
}
}
print v
}' file
测试:
kent$ awk -v c=1 -v t=11.6 '{a[NR]=$c}END{
asort(a);d=a[NR]-t;d=d<0?-d:d;v = a[NR]
for(i=NR-1;i>=1;i--){
m=a[i]-t;m=m<0?-m:m
if(m<d){
d=m;v=a[i]
}
}
print v
}' f
11.700000
简短的解释。
我不会解释每一行代码,它的作用。只是告诉一点做这项工作的想法。
- 首先读取给定列中的所有元素,保存在数组中
- 对数组进行排序。
- 从数组中取出最后一个元素(最大的数字)。将其分配给 var
v
,并计算它与给定目标之间的差异,将其(绝对值)保存在d
- 从数组循环的第二个最后一个元素到第一个。如果元素和目标之间的差异(绝对值)小于
d
,用差异覆盖d
,也将当前元素保存到v
- 打印v,循环之后,v就是答案。
一些注意事项:
- 有优化逻辑的空间。例如,我们不必遍历整个数组。只需比较
d(abs)
,如果 new diff > d,我们可以停止循环。
- 由于排序,这个算法是
O(nlogn)
. 其实这个问题可以通过O(n)
. 如果您的输入数据很大,并且在最坏的情况下(例如,您的列的值在 range 500-99999999999
,但您的目标是 1。)您可能希望避免排序。但我认为性能不是你的问题。