awk를 사용하여 여러 줄을 하나로 결합

awk를 사용하여 여러 줄을 하나로 결합

저는 다음 형식의 매우 큰 데이터 세트로 작업하고 있습니다.

chr1 45162 . . C T 
chr1 45162 . . C T
chr1 45162 A . . T
chr1 45162 . . C T
chr1 45257 A . . T
chr1 45257 A . . T
chr1 45413 A . . T
chr1 46844 A . C .
chr1 72434 A G . .
chr1 72434 A G . .
chr1 72434 A G . .
chr1 72434 A G . .
chr1 72515 A . C .
chr1 72515 A . . T
chr1 77689 A G . .    

내가 원하는 출력은 다음과 같습니다.

chr1 45162 A . C T
chr1 45257 A . . T
chr1 45413 A . . T
chr1 46844 A . C .
chr1 72434 A G . .
chr1 72515 A . C T
chr1 77689 A G . .

기본적으로 열 2의 각 고유 값에 대해 별도의 행에 저장될 수 있는 모든 속성을 확인해야 합니다.

그래서 내가 가진 경우 :

chr1 100 A . C .
chr1 100 . G . T

출력에 원하는 줄은 다음과 같습니다.

chr1 100 A G C T

나는 잘 작동한다고 생각하는 스크립트를 가지고 있지만 너무 느립니다. awk간단한 스크립트를 사용하여 이 작업을 수행 하는 더 쉬운 방법이 있어야 한다고 생각합니다 .

내 현재 버전은 다음과 같습니다.http://ideone.com/e.js/ETBRz3 하지만 제가 말했듯이 awk.

모든 제안을 환영합니다.

(만약 단순화한다면, 빈 필드가 "." 문자 대신 빈 문자열이 되도록 이 파일을 생성하는 스크립트를 수정하여 수정할 수 있습니다.)

답변1

한 가지 방법은 다음과 같습니다.

$ awk '$2!=old && NR>1 {for (i=1;i<=NF;i++) printf a[old","i]" "; print"";} {old=$2;for (i=1;i<=NF;i++) {if (a[$2","i]=="." ||  a[$2","i]=="") a[$2","i]= $i}} END{for (i=1;i<=NF;i++) printf a[old","i]" "; print"";}' file 
chr1 45162 A . C T 
chr1 45257 A . . T 
chr1 45413 A . . T 
chr1 46844 A . C . 
chr1 72434 A G . . 
chr1 72515 A . C T 
chr1 77689 A G . . 

어떻게 작동하나요?

  • $2!=old && NR>1 {for (i=1;i<=NF;i++) printf a[old","i]" "; print"";}

    첫 번째 행 이후 두 번째 열의 새 값을 만날 때마다 이전 값의 결과를 인쇄합니다.

  • old=$2;for (i=1;i<=NF;i++) {if (a[$2","i]=="." || a[$2","i]=="") a[$2","i]= $i}

    a현재 행의 값으로 배열을 업데이트합니다.

    GNU에는 awk멋진 2차원 배열이 있습니다. 그러나 호환성상의 이유로 POSIX 호환 대안을 사용합니다.

  • END{for (i=1;i<=NF;i++) printf a[old","i]" "; print"";}

    마지막 줄 다음에 정보의 마지막 부분을 인쇄합니다.

답변2

정렬되지 않은 행의 또 다른 변형:

awk '{
k[$2]=$1;
for(i=3;i<7;i++){
  if(l[$2,i]=="." || l[$2,i]=="")
    l[$2,i]=$i;
  }
}
END{
for(n in k){
  printf("%s %s ",k[n],n);
  for(m=3;m<7;m++)
    printf("%s ", l[n,m]);
  print "";
  }
 }' file

간단한 설명:

k파일 스크립트를 통해 두 개의 연관 배열( with field#2as index 및 lwith index ) 을 만듭니다 field#2,Next_fields_number. 파일의 모든 행이 전달되면 스크립트는 두 개의 루프를 시작하여 첫 번째 배열과 두 번째 배열의 필드를 인쇄합니다.

답변3

일방 perl통행:

$ perl -anle '
  for (2..$#F) {
    $h{join(" ",@F[0..1])}->{$_} ||= $F[$_];
    $h{join(" ",@F[0..1])}->{$_} = $F[$_] if $F[$_] ne ".";
  }
  END { print "$_ @{$h{$_}}{sort keys %{$h{$_}}}" for sort keys %h }
' file
chr1 45162 A . C T
chr1 45257 A . . T
chr1 45413 A . . T
chr1 46844 A . C .
chr1 72434 A G . .
chr1 72515 A . C T
chr1 77689 A G . .

관련 정보