如何在最接近$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
}
'
但我无法适应它
答案 0 :(得分:5)
我只是按距离对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-
答案 1 :(得分: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
计算为绝对 d ifference
在该值与 t arget值之间,
t
(在命令行上设置为$VariableNumber
的值,
根据你的例子,它可能是30)。
然后它构造一个数组 e ntry,e
,
由差异组成,
与#
和原始数字连接在一起。
然后将此数组条目添加到 a rray a
。
前五个输入值只是放入数组元素1到5中。
之后,每个数字都附加到数组中
通过放入元素6.然后对数组进行排序。
由于数组条目以 d ifference值开头,
接近 t arget的数字
( d ifference值为低)
被排序到数组的开头,
和远离 t arget的数字
被排序到数组的末尾。
(指定"@val_num_asc"
将值排序为数字而不是字符串。
如果不这样做,10
和20
的差异将排在3
和4
之下。)
然后删除第6个元素(距离目标最远的元素)。
最后(在到达数据的END时),我们
#
通过搜索正则表达式.*#
并代替(gsub
)什么都没有。
然后打印原始值。显然,如果你想查看第一个列,
您可以更改脚本中$1
的所有匹配项。
(您在问题中显示的脚本
演示了如何在运行时指定列号。)
并且,如果你想要一些除最近的五个之外的数字,
只需更改5
的所有外观。
(我本可以在第9和第11行提到a[6]
;
我写了a[5+1]
来促进简单的参数化。)
答案 2 :(得分:0)
另一个,对于所有awk(已对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
执行时间是线性的,最坏的情况是值数组的大小乘以记录计数,因此仍是线性的(对吗?:)。