如何删除制表符分隔的文本文件中的重复值

如何删除制表符分隔的文本文件中的重复值

我有一个制表符分隔的列文本,如下所示

A      B1      B1     C1
B      B2      D2 
C      C12     C13    C13
D      D3      D5      D9
G      F2      F2   

我怎样才能像下面这样转换上表

A      B1     C1
B      B2     D2 
C      C12    C13
D      D3     D5     D9
G      F2   

我已经提取了我的真实数据文件,它是一个制表符分隔的文件,我已经尝试了您(Stéphane Chazelas?)发布的命令行,它工作正常,但无法删除最后一列上的重复项

A  CD274    PDCD1LG2  CD276   PDCD1LG2  CD274
B  NEK2     NEK6      NEK10   NEK10     NEKL-4
C  TNFAIP3  OTUD7B    OTUD7B  TNFAIP3   TNFAIP3
D  DUSP16   DUSP4     DUSP8   VHP-1     DUSP8
E  AGO2     AGO2      AGO2    AGO2      AGO2

输出需要如下

A  CD274    CD276   PDCD1LG2
B  NEK2     NEK6    NEK10     NEKL-4
C  TNFAIP3  OTUD7B
D  DUSP16   DUSP4   DUSP8     VHP-1
E  AGO2

答案1

第一组示例数据:

$ awk -vOFS='\t' '{ r=""; delete t; for (i=1;i<=NF;++i) { if (!t[$i]++) { r = r ? r OFS $i : $i } } print r }' file
A       B1      C1
B       B2      D2
C       C12     C13
D       D3      D5      D9
G       F2

第二组示例数据(相同的awk脚本):

$ awk -vOFS='\t' '{ r=""; delete t; for (i=1;i<=NF;++i) { if (!t[$i]++) { r = r ? r OFS $i : $i } } print r }' file
A       CD274   PDCD1LG2        CD276
B       NEK2    NEK6    NEK10   NEKL-4
C       TNFAIP3 OTUD7B
D       DUSP16  DUSP4   DUSP8   VHP-1
E       AGO2

该脚本逐行读取输入文件file,并且对于每一行,它都会遍历每个字段,构建输出行r.如果字段中的值已添加到输出行(由t已用字段值的查找表 确定),则该字段将被忽略,否则将被添加。

当输入行的所有字段都已处理完毕后,将输出构造的行。

-vOFS='\t'输出字段分隔符在命令行上设置为制表符。


剧本awk揭晓:

{
    r = ""
    delete t

    for (i = 1; i <= NF; ++i) {
        if (!t[$i]++) {
            r = r ? r OFS $i : $i
        }
    }

    print r
}

答案2

sed/tr、uniq 和 Paste

while read -r l; do sed 's/\t/\n/g' <<< "$l" | uniq | paste -s; done < test

或 POSIX 兼容:

while read -r l; do echo "$l" | tr '\t' '\n' | uniq | paste -s -; done < test

对于文件,test这将逐行用Tab换行符替换所有字符,运行以删除重复项并再次uniq用字符替换换行符。Tab

$ cat test
A       B1      B1      C1
B       B2      D2
C       C12     C13     C13
D       D3      D5      D9
G       F2      F2

$ while read -r l; do sed 's/\t/\n/g' <<< "$l" | uniq | paste -s; done < test
A       B1      C1
B       B2      D2
C       C12     C13
D       D3      D5      D9
G       F2

注意:该解决方案将不是适用于多行的重复项,C1例如

A       B1      B1      C1
C1      B       B2      D2

答案3

也许是这样的:

gawk -vRS='\\s*\\S*' -vORS= '{$0=RT};$1!=prev;{prev=$1}'

RS=pattern...技巧{$0=RT}允许您处理定义为与模式匹配的部分的记录。

所以在这里,我们将输入切成<whitespace><non-whitespace> $0记录,<non-whitespace>进入$1(第一个也是唯一的字段)。我们正在打印$1不等于前一条的记录。

在这样的输入上:

A      B1      B1     C1
B      B2      D2 
C      C12     C13    C13
D      D3      D5      D9
G      F2      F2

记录是:

[A][ B1] [ B1] [ C1][
B][ B2][ D2][
C][ C12][ C13] [ C13] [
D][ D3][ D5][ D9][
G][ F2] [ F2] [
]

但不适用于您的第二个示例,请注意它可能会删除一些换行符。

答案4

perl

每行都有独特的单词:

perl -MList::Util=uniq -lape '$_ = join "\t", uniq @F'

全球唯一的单词:

perl -lape '$_ = join "\t", grep {!$count{$_}++} @F'

或者只考虑从第二行开始的每行单词:

perl -lape '$_ = join "\t", shift(@F), grep {!$count{$_}++} @F'

相关内容