2010-06-04 10 views
4

를 사용한 컬럼에서 중복 값을 제거 I 아래 다음 형식으로 큰 데이터 파일을 가지고awk의 Uniq; AWK

ENST00000371026 WDR78,WDR78,WDR78, WD repeat domain 78 isoform 1,WD repeat domain 78 isoform 1,WD repeat domain 78 isoform 2, 
ENST00000371023 WDR32 WD repeat domain 32 isoform 2 
ENST00000400908 RERE,KIAA0458, atrophin-1 like protein isoform a,Homo sapiens mRNA for KIAA0458 protein, partial cds., 

열 탭 분리된다. 열 내의 여러 값은 쉼표로 구분됩니다. 나는이 같은 결과 두 번째 열에서 중복 값을 제거하고 싶습니다 :

ENST00000371026 WDR78 WD repeat domain 78 isoform 1,WD repeat domain 78 isoform 1,WD repeat domain 78 isoform 2, 
ENST00000371023 WDR32 WD repeat domain 32 isoform 2 
ENST00000400908 RERE,KIAA0458 atrophin-1 like protein isoform a,Homo sapiens mRNA for KIAA0458 protein, partial cds., 

나는 아래에 다음 코드를 시도하지만 중복 값을 제거하지 않는 것 같습니다.

awk ' 
BEGIN { FS="\t" } ; 
{ 
    split($2, valueArray,","); 
    j=0; 
    for (i in valueArray) 
    { 
    if (!(valueArray[i] in duplicateArray)) 
    { 
     duplicateArray[j] = valueArray[i]; 
     j++; 
    } 
    }; 
    printf $1 "\t"; 
    for (j in duplicateArray) 
    { 
    if (duplicateArray[j]) { 
     printf duplicateArray[j] ","; 
    } 
    } 
    printf "\t"; 
    print $3 

}' knownGeneFromUCSC.txt 

어떻게 열 2의 중복을 올바르게 제거 할 수 있습니까?

답변

6

스크립트는 때문에 NR==2의 파일의 두 번째 레코드 (라인)에 작용한다. 나는 그것을 꺼냈다. 그러나 그것은 당신이 의도 한 것일 수있다. 그렇다면 다시 넣어야합니다.

인덱스 아닌 값이 존재하는 오퍼레이터 in 검사, 그래서 duplicateArray 그 지표로서 valueArray의 값을 사용하는 결합 배열 *했다. 이렇게하면 루프 내의 루프에서 두 배열을 모두 반복하지 않아도됩니다.

split 문은 네 개의 필드가 아니라 세 가지가 내가 초래 널 값을 인쇄에서 그것을 유지하는 if을 추가 이상으로 "WDR78, WDR78, WDR78", "WDR78"를보고 인쇄되는 경우 if weren 히 거기있어.

* 실제로 AWK의 모든 배열은 연관되어 있습니다.

awk ' 
BEGIN { FS="\t" } ; 
{ 
    split($2, valueArray,","); 
    j=0; 
    for (i in valueArray) 
    { 
    if (!(valueArray[i] in duplicateArray)) 
    { 
     duplicateArray[valueArray[i]] = 1 
    } 
    }; 
    printf $1 "\t"; 
    for (j in duplicateArray) 
    { 
    if (j) # prevents printing an extra comma 
    { 
     printf j ","; 
    } 
    } 
    printf "\t"; 
    print $3 
    delete duplicateArray # for non-gawk, use split("", duplicateArray) 
}' 
3

죄송합니다, 나는 당신이 AWK에 대해 질문 알고 ...하지만 펄이 훨씬 더 간단하게 :

$ perl -n -e ' @t = split(/\t/); 
    %t2 = map { $_ => 1 } split(/,/,$t[1]); 
    $t[1] = join(",",keys %t2); 
    print join("\t",@t); ' knownGeneFromUCSC.txt 
+0

+1 감사합니다. 이 솔루션은 제 것보다 낫습니다. 그러나 나는 왜 내 솔루션이 작동하지 않았는지 궁금해. 나는 그 이유 때문에 받아 들여진 대답을 일시적으로 세우는 일을 보류 할 것이다. 어쩌면 누군가 awk에서 그것을하는 법을 알게 될 것입니다. –

2

순수 배시 4.0 (한 결합 배열)

declare -a part       # parts of a line 
declare -a part2       # parts 2. column 
declare -A check       # used to remember items in part2 

while read line ; do 
    part=($line)       # split line using whitespaces 
    IFS=','         # separator is comma 
    part2=(${part[1]})      # split 2. column using comma 
    if [ ${#part2[@]} -gt 1 ] ; then   # more than 1 field in 2. column? 
    check=()        # empty check array 
    new2=''        # empty new 2. column 
    for item in ${part2[@]} ; do 
     ((check[$item]++))     # remember items in 2. column 
     if [ ${check[$item]} -eq 1 ] ; then # not yet seen? 
     new2=$new2,$item     # add to new 2. column 
     fi 
    done 
    part[1]=${new2#,}      # remove leading comma 
    fi 
    IFS=$'\t'        # separator for the output 
    echo "${part[*]}"      # rebuild line 
done < "$infile" 
3

펄 :

perl -F'\t' -lane' 
    $F[1] = join ",", grep !$_{$_}++, split ",", $F[1]; 
    print join "\t", @F; %_ =(); 
    ' infile 

AWK는 :

awk -F'\t' '{ 
    n = split($2, t, ","); _2 = x 
    split(x, _) # use delete _ if supported 
    for (i = 0; ++i <= n;) 
    _[t[i]]++ || _2 = _2 ? _2 "," t[i] : t[i] 
    $2 = _2 
    }-3' OFS='\t' infile 

AWK 스크립트의 라인 (4)이 원래의 순서를 유지하는 데 사용 f 고유 값을 필터링 한 후 두 번째 필드의 값.