2010-06-04 50 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语句看到“WDR78,WDR78,WDR78,”四场,而不是三个,所以我说的if保持它打印一个空值,这将导致“ WDR78,”正在打印如果if间没有在那里。

*在现实中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的使这更简单:

$ 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中做到这一点。 – 2010-06-05 00:07:39

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:

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行是用于保存原始的订单o f在过滤唯一值后,在第二个字段中的值。