2010-06-04 6 views
4

J'ai un grand fichier de données dans le format ci-dessous:Uniq in awk; la suppression des doublons dans une colonne en utilisant 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., 

Les colonnes sont séparées par des tabulations. Les valeurs multiples dans les colonnes sont séparées par des virgules. Je voudrais supprimer les valeurs en double dans la deuxième colonne pour aboutir à quelque chose comme ceci:

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., 

J'ai essayé le code suivant ci-dessous, mais il ne semble pas supprimer les valeurs en double.

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 

Comment puis-je supprimer les doublons dans la colonne 2 correctement?

Répondre

6

Votre script agit uniquement sur le deuxième enregistrement (ligne) dans le fichier en raison de NR==2. Je l'ai sorti, mais c'est peut-être ce que vous avez l'intention de faire. Si oui, vous devriez le remettre.

Les in opérateur vérifie la présence de l'indice , pas la valeur, donc je fait duplicateArray un tableau associatif * qui utilise les valeurs de valueArray comme ses indices. Cela évite d'avoir à parcourir les deux tableaux dans une boucle dans une boucle.

La déclaration split voit « WDR78, WDR78, WDR78, » comme quatre champs plutôt que trois donc j'ajouté un if pour l'empêcher de l'impression d'une valeur nulle qui aurait pour conséquence «WDR78 », en cours d'impression si le if weren n'est pas là.

* En réalité, tous les tableaux dans AWK sont associatifs.

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

Désolé, je sais que vous avez parlé awk ... mais Perl rend ce beaucoup plus simple:

$ 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 Merci beaucoup pour la réponse. Cette solution est meilleure que la mienne. Cependant, je suis également curieux de savoir pourquoi ma solution n'a pas fonctionné. Je tiendrai sur la définition d'une réponse acceptée temporairement pour cette raison. Peut-être que quelqu'un saura comment le faire dans awk. –

2

Bash pur 4.0 (un tableau associatif):

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:

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 

La ligne 4 dans le script awk utilisé pour préserver l'ordre d'origine o f les valeurs dans le deuxième champ après filtrage des valeurs uniques.

Questions connexes