找到最接近的前5名而不是最近的?

问题描述 投票:2回答:3

您如何在最接近$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
    }
'

但我无法适应它

text-processing
3个回答
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-

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"将值排序为数字而不是字符串。如果没有这个,1020的差异将排在34之下。)然后删除第6个元素(距离目标最远的元素)。

最后(在达到数据的结尾时),我们

  • 检查记录数是否≤5。如果是,则对数组进行排序,因为它仍然是输入数据的顺序。 (可以说,这一步是可选的。)
  • 因为每个元素都是数组,通过搜索正则表达式#并用(.*#)替换来消除差异和gsub。然后打印原始值。

显然,如果要查看第一列的其他列,可以在脚本中更改$1的所有匹配项。 (您在问题中显示的脚本演示了如何在运行时指定列号。)并且,如果您想要除最接近的五个之外的其他数字,只需更改5的所有外观。 (我本可以在第9行和第11行中提到a[6];我写了a[5+1]来促进简单的参数化。)


0
投票

另一个,对于所有的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

执行时间是线性的,最坏的情况是值数组的大小乘以记录计数,所以仍然是线性的(对吗?:)。

© www.soinside.com 2019 - 2024. All rights reserved.