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)절대값의 기능을 수행하는 표현식의 일부

관련 정보