이 문제에 대한 Perl 또는 awk 솔루션이 있습니까?

이 문제에 대한 Perl 또는 awk 솔루션이 있습니까?

입력 파일이 있습니다(입력.txt) 아래와 같습니다.

id1      id2       name    weight 
53723848 12651711 timburnes 1.36667
53530214 12651711 timburnes 1.51191
53723848 53530214 timburnes 1.94
764157 52986038 ericcartman 0.861145
56797854 764157 ericcartman 1.35258
56797854 52986038 ericcartman 1.73781

참고하세요첫 번째 줄은 실제 파일의 일부가 아니므로 명확성을 위해 여기에 추가했습니다..

id1및 의 값을 id22개의 별도 파일로 추출하려고 합니다 .고유.txt그리고중복.txt.

weight열 값이 1.5보다 크면중복 ID. 이 경우 값을 파일 id1로 이동하고 값을 파일로 이동하겠습니다 .unique.txtid2duplicate.txt

가중치 열이 1.5보다 작으면 중복된 값이 없다는 의미입니다. 따라서 이 경우 에는 id1id2고유.txt파일.

따라서 위의 입력에 대해 다음과 같은 출력을 기대합니다.

을 위한고유.txt파일,

53723848 timburnes
764157 ericcartman
56797854 ericcartman

을 위한중복.txt파일,

12651711 timburnes
53530214 timburnes
52986038 ericcartman

아래 코드를 사용하여 중복 항목을 찾을 수 있습니다.

네 번째 열을 기준으로 1.5보다 큰 값을 얻으려면

awk -F" " '$4 >= 1.5 { print $1" " $2" " $3" " $4}' file1.txt > Output.txt

이제 1.5보다 큰 값의 경우 아래 코드를 사용하여 이름을 기반으로 중복 ID를 병합할 수 있습니다.

  perl -ane 'foreach(@F[0..1]){$k{$F[2]}{$_}++}
           END{
                foreach $v (sort keys(%k)){
                    print "$_ " foreach(keys(%{$k{$v}})); 
                    print "$v\n"
                }; 
            } ' Output.txt

그러나 위의 접근 방식에서는 원하는 방식으로 출력을 얻을 수 없습니다.

편집하다:

입력에 대한 명령을 아래와 같이 실행하고 있습니다.

awk '{
      if ($4 > 1.5) { 
          if (++dup[$2] == 1)  print $2, $3 > "duplicate.txt"
      } 
      else
          if (++uniq[$1] == 1) print $1, $3 > "unique.txt" 
}' << END
17412193 43979400 ericcartman 2.16667
21757330 54678379 andrewruss 0.55264
END 

나는 다음과 같이 출력을 얻고 있습니다.

-bash-3.2$ cat unique.txt
21757330 a.andreev
-bash-3.2$ cat duplicate.txt
43979400 ericcartman

그러나 내가 기대하는 결과는 다음과 같습니다.

cat unique.txt
17412193 ericcartman
21757330 andrewruss
54678379 andrewruss
cat duplicate.txt
43979400 ericcartman

답변1

해결책 은 다음과 같습니다 awk.

$ awk '
    $4 < 1.5 {
      uniq[$1] = $3;
      uniq[$2] = $3;
      next;
  }
  {
      uniq[$1] = $3;
      dup[$2] = $3;
      delete uniq[$2];
  }
  END {
    print "--unique.txt--";
    for(i in uniq) {
        print i,uniq[i]
    }
    print "";
    print "--duplicate.txt--";
    for(i in dup) {
        print i,dup[i]
    }
    }' file
--unique.txt--
764157 ericcartman
56797854 ericcartman
53723848 timburnes

--duplicate.txt--
53530214 timburnes
52986038 ericcartman
12651711 timburnes

두 번째 예를 들면 다음과 같습니다.

$ awk '
    $4 < 1.5 {
      uniq[$1] = $3;
      uniq[$2] = $3;
      next;
  }
  {
      uniq[$1] = $3;
      dup[$2] = $3;
      delete uniq[$2];
  }
  END {
    print "--unique.txt--";
    for(i in uniq) {
        print i,uniq[i]
    }
    print "";
    print "--duplicate.txt--";
    for(i in dup) {
        print i,dup[i]
    }
    }' << END
> 17412193 43979400 ericcartman 2.16667
> 21757330 54678379 andrewruss 0.55264
END
--unique.txt--
21757330 andrewruss
54678379 andrewruss
17412193 ericcartman

--duplicate.txt--
43979400 ericcartman

답변2

$ awk '{
      if ($4 > 1.5) { 
          if (++dup[$2] == 1)  print $2, $3 > "duplicate.txt"
      } 
      else
          if (++uniq[$1] == 1) print $1, $3 > "unique.txt" 
}' << END
53723848 12651711 timburnes 1.36667
53530214 12651711 timburnes 1.51191
53723848 53530214 timburnes 1.94
764157 52986038 ericcartman 0.861145
56797854 764157 ericcartman 1.35258
56797854 52986038 ericcartman 1.73781
END

$ cat unique.txt 
53723848 timburnes
764157 ericcartman
56797854 ericcartman

$ cat duplicate.txt 
12651711 timburnes
53530214 timburnes
52986038 ericcartman

답변3

여기 Perl이 있습니다:

perl -lane '$F[3]>1.5 ? print STDERR "$F[1] $F[2]" : print STDOUT "$F[0] $F[2]"'\
 input.txt 2> duplicate.txt > unique.txt

여기서는 중복 항목을 확인하지 않습니다. 귀하의 질문을 올바르게 이해했다면 이미 그렇게 하신 것이며, 속이는 항목인지 여부는 마지막 필드의 값에 따라 달라집니다. 제가 잘못 이해하고 있는 부분이 있으면 알려주시면 업데이트하겠습니다.

위의 코드는

$ cat duplicate.txt 
12651711 timburnes
53530214 timburnes
52986038 ericcartman

$ cat unique.txt 
53723848 timburnes
764157 ericcartman
56797854 ericcartman

관련 정보