使用 awk 从另一个文件中查找最接近的值

使用 awk 从另一个文件中查找最接近的值

我有 2 个文件。

文件1:

123 pattern1   
452 pattern2
601 pattern3

文件2:

12  a
34  b
88  ee
120 f
333 qw
400 oo
566 i
993 o

我想要的是从 file2 的第一列中找到与 file1 第一列中的每一行最接近的值,然后将相应的第二列添加到 file2 到 file1 (在新文件中)

这两个文件中都没有重复的值。

期望的输出:

123 pattern1    f   
452 pattern2    oo
601 pattern3    i

我试图使用 awk,但它还远远没有工作:/

awk 'NR==FNR { seq[$2]=$1; next }
{
    d = $1 - seq[$2];
    d = d < 0 ? -d : d;
    v = $1;
    next
}
{
    m = $1 - seq[$2];
    m = m < 0 ? -m : m
}
m < d {
    d = m;
    v = $1
}
{ print $0 }' file1.txt file2.txt

答案1

博多已经指出您的代码存在问题并更正它们。我正在给出替代答案。

仅使用awk。这是本质上与 Bodo 的答案相同,但它不会将第一个文件中的数据拆分为单独的数组。它也不使用神奇的数字常量(在其代码中为 -1)来初始化所看到的最小距离,而是使用以下事实:awk当解释为字符串时,未设置的值是空的。

awk '
    NR == FNR { num[$0] = $1; next }
    {
        for (a in num) {
            d = (num[a]-$1)^2
            if (min[a] == "" || d < min[a]) {
                min[a] = d; symb[a] = $2
            }
        }
    } 
    END { for (a in symb) print a, symb[a] }' file1 file2

其他方法:

join -1 3 -2 3 file1 file2 |
awk '{ print ($1-$3)^2, $0 }' |
sort -k 1,1n | sort -su -k 2,3  |
awk '{ print $2, $3, $5 }'

上面首先使用join不存在的字段来创建所有输入数据的关系叉积(它将一个文件的每一行与另一个文件的所有行组合起来)。

该数据将如下所示:

 123 pattern1 12 a
 123 pattern1 34 b
[etc.]
 601 pattern3 566 i
 601 pattern3 993 o

然后,它计算距离度量并将其插入作为新的第一列:

12321  123 pattern1 12 a
7921  123 pattern1 34 b
[etc.]
1225  601 pattern3 566 i
153664  601 pattern3 993 o

这两个调用sort首先根据距离度量对这些数据进行数字排序,然后使用第一个文件中的数据作为排序键并进行稳定的唯一排序。这将丢弃第一个文件中除第一个数据实例之外的所有数据,在本例中留下三行:

9  123 pattern1 120 f
2704  452 pattern2 400 oo
1225  601 pattern3 566 i

由此,我们挑选出我们感兴趣的列awk

123 pattern1 f
452 pattern2 oo
601 pattern3 i

答案2

您的脚本中有几个问题awk。第二个动作块没有条件并以 结束next。这就是为什么其他块永远不会被执行的原因。

使用第二个文件中的字段 2 作为索引seq没有意义,因为字段 2 中的值在 file1 和 file2 之间不同。

awk 'NR==FNR {
    seq[NR] = $1;
    name[NR] = $2;
    delta[NR] = -1;
    count = NR;
    next
}
{
    for(i = 1; i <= count; i++) {
       d = $1 - seq[i];
       d = d < 0 ? -d : d;
       if((delta[i] < 0) || (d < delta[i])) {
            delta[i] = d;
            val[i] = $2;
       }
    }
}
END {
    for(i = 1; i <= count; i++) {
       printf "%s %s\t%s\n", seq[i], name[i], val[i]
    }
}' file1.txt file2.txt

印刷

123 pattern1    f
452 pattern2    oo
601 pattern3    i

答案3

如果更改文件的顺序,会更紧凑一些。

awk '
NR==FNR {A[$1]=$2; next}
{arg=1000
        for(i in A){
                cmp = sqrt(($1-i)^2)
                if(cmp < arg)
                        {arg=cmp; third=A[i]}
                }
        print $0, third}
' file2 file1

表达式的部分sqrt(X^2)执行绝对值的功能

相关内容