두 번째 파일의 정보를 기반으로 첫 번째 파일의 특정 줄을 어떻게 삭제할 수 있나요?

두 번째 파일의 정보를 기반으로 첫 번째 파일의 특정 줄을 어떻게 삭제할 수 있나요?

다음과 같은 파일이 있습니다.

파일 1:

    1   2       0.000
    1   3       0.213
    1   4       0.014
    1   5       0.001
    1   6       0.555
    1   7       0.509
    1   8       0.509
    3   4       0.995
    3   5       0.323
    3   6       0.555
    3   7       0.225
    3   8       0.000
    4   5       0.095
    4   6       0.058
    4   7       0.335
    4   8       0.000
    5   6       0.995
    5   7       0.658
    5   8       0.000
    6   7       0.431
    6   8       0.000
    7   8       0.000

파일 2:

1
3 
4
5 6 7

파일 2에서 숫자 쌍이 연속적으로 관찰되는 파일 1의 행을 유지하고 싶습니다. 여기서는 파일 2에서 5, 6, 7만 관찰됩니다. 따라서 각 숫자 쌍은 파일 1에 남아 있어야 합니다. 따라서 출력은 다음과 같습니다.

5   6       0.995
5   7       0.658
6   7       0.431

어떤 제안이 있습니까(실제 데이터가 크고 숫자가 1부터 시작하지 않을 수 있다는 점을 고려)?

답변1

perl해결책이 괜찮다 면 . file1의 컬럼1과 컬럼2 데이터는 컬럼1의 값이 항상 컬럼2보다 작도록 정렬되어 있다고 가정합니다.

$ perl -lane '
    if(!$nf)
    {
        if($#F > 0)
        {
            foreach $i (0..$#F)
            {
                $h{"-$F[$i]-$F[$_]-"}++ foreach ($i+1..$#F)
            }
        }
        $nf++ if eof;
    }
    else
    {
        print if $h{"-$F[0]-$F[1]-"}
    }
' file2 file1
    5   6       0.995
    5   7       0.658
    6   7       0.431
  • 먼저, file2에 쌍으로 키의 해시를 구축합니다(다시 숫자가 오름차순이라고 가정).
    • 및 대 등 의 -불일치를 방지하기 위해 두 개의 열 값을 둘러쌉니다 .11201120
  • 그런 다음 file1 행에 대해 키가 있으면 해당 행을 인쇄하십시오.


file2로 변경된 경우

$ cat file2
1
3 4
5 6 7 8

$ perl -lane '
    if(!$nf)
    {
        if($#F > 0)
        {
            foreach $i (0..$#F)
            {
                $h{"-$F[$i]-$F[$_]-"}++ foreach ($i+1..$#F)
            }
        }
        $nf++ if eof;
    }
    else
    {
        print if $h{"-$F[0]-$F[1]-"}
    }
' file2 file1
    3   4       0.995
    5   6       0.995
    5   7       0.658
    5   8       0.000
    6   7       0.431
    6   8       0.000
    7   8       0.000

답변2

awk를 사용하세요.

첫 번째 awk 명령은 모든 쌍을 포함하는 파일을 생성합니다. 두 번째 awk 명령은 쌍 파일을 배열로 한 번 읽어 일치하는 모든 행을 인쇄합니다.

awk 'NF>1{for(i=1;i<=NF;i++) for(j=i+1;j<=NF;j++) print $i,$j;}' file2 > /tmp/pairs
awk 'BEGIN{while((getline <"/tmp/pairs") > 0) pair[$1,$2]=1; close("/tmp/pairs")} ($1,$2) in pair' file1

두 번째 명령에는 많은 메모리가 필요할 수 있습니다! 파일이 순서대로 정렬되어 있으면 어떻게든 배열을 피하고 두 파일을 동시에 읽을 수 있습니다. 최종 실행 전에 쌍 파일을 보려면 두 가지 명령을 사용합니다.

여기의 코드는 단일 명령과 동일하며 읽을 수 있는 형식입니다.

awk '
  BEGIN {
    f="file2"
    while((getline <f) > 0)
      for(i=1;i<=NF;i++)
        for(j=i+1;j<=NF;j++)
          pair[$i,$j]=1;
    close(f);
  }
  ($1,$2) in pair
' file1

참고로file1(22 mill.lines), file2(4 mill.lines)에 대해 일부 벤치마크를 실행하여 2 mill.lines를 생성했습니다. 라인 출력.

  • gawk: 9.6초, 275M 메모리
  • mawk: 20.7초, 134M 메모리
  • Sundeep의 Perl 답변: 31.9초, 231M 메모리

관련 정보