从文本文件中删除每个单独列中的重复项

Posted

技术标签:

【中文标题】从文本文件中删除每个单独列中的重复项【英文标题】:Remove duplicates in each individual column from a text file 【发布时间】:2021-11-07 07:13:07 【问题描述】:

我有一个包含 7 个制表符分隔列的文本文件。每列都有不同数量的行,其中的值可以重复。我想删除重复项,以便每列只有该特定列的唯一值。举个例子:

输入

C1  C2  C3  C4  C5  C6  C7
111 111 222 333 111 222 777 
222 111 333 333 222 333 666
222 111 444 111 333 555 555
333 444 555 222 444 666 444
444 666 555 777 555 666 333
444 777 777 555 666 888 333
777 888 999 666 888                 
999

输出

C1  C2  C3  C4  C5  C6  C7
111 111 222 333 111 222 777
222 444 333 111 222 333 666
333 666 444 222 333 555 555
444 777 555 777 444 666 444
777 888 777 555 555 888 333
999     999 666 666 
                888

我想我需要使用 awk 来打印每一列并单独使用 sort -u,然后将这些输出粘贴在一起。那么,有没有一种方法可以创建一个循环,对于文本文件中的 i 列,将打印每一列 | sort - u,然后将它们全部粘贴在一起?

提前致谢, 卡洛斯

【问题讨论】:

转置,然后在行中制作唯一编号,然后再次转置。 paste <(awk '!seen[$1]++ && $0=$1' file) <(awk '!seen[$2]++ && $0=$2' file) <(awk '!seen[$3]++ && $0=$3' file) <(awk '!seen[$4]++ && $0=$4' file) <(awk '!seen[$5]++ && $0=$5' file) <(awk '!seen[$6]++ && $0=$6' file) <(awk '!seen[$7]++ && $0=$7' file) ;-) 谢谢@Cyrus,它适用于这个特定的文件。但是,将来我将使用具有随机列数的文件来执行此操作。有没有办法做类似的事情: for i columns do paste @Carlos Cyrus 是在开玩笑,请注意他们评论末尾的笑脸表情符号。 @EdMorton:是的,我已经看到灾难即将到来,它不会停留在 7 列。 【参考方案1】:

使用perl 代替它支持真正的多维数组:

perl -lane '
    for my $n (0..$#F) 
      if (!exists $$vals[$n]$F[$n]) 
        push @$cols[$n], $F[$n];
        $$vals[$n]$F[$n] = 1;
      
    
    END 
      for (1..$.) 
        my @row;
        for my $n (0..$#cols) 
          push @row, shift @$cols[$n];
        
        print join("\t", @row);
     
' input.txt

【讨论】:

【参考方案2】:

在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ cat tst.awk
BEGIN  FS=OFS="\t" 

    for (colNr=1; colNr<=NF; colNr++) 
        val = $colNr
        if ( !seen[colNr,val]++ ) 
            rowNr = ++colRowNrs[colNr]
            vals[rowNr,colNr] = val
            numRows = (rowNr > numRows ? rowNr : numRows)
        
    
    numCols = (NF > numCols ? NF : numCols)

END 
    for (rowNr=1; rowNr<=numRows; rowNr++) 
        for (colNr=1; colNr<=numCols; colNr++) 
            val = vals[rowNr,colNr]
            printf "%s%s", val, (colNr<numCols ? OFS : ORS)
        
    

$ awk -f tst.awk file
C1      C2      C3      C4      C5      C6      C7
111     111     222     333     111     222     777
222     444     333     111     222     333     666
333     666     444     222     333     555     555
444     777     555     777     444     666     444
777     888     777     555     555     888     333
999             999     666     666
                                888

【讨论】:

【参考方案3】:

假设

整个输出结果的 (awk) 数组将适合内存 列数和行数可变

一个想法由一个(稀疏的)二维值数组组成,其中数组结构如下所示:

values[<column#>][<row#>]=<unique_cell_value>

使用单个 awk 调用的一个想法 a) 需要单次通过输入文件,而 b) 不需要任何转置/粘贴(以防万一任何人都认真对待赛勒斯的评论/建议):

awk '
BEGIN   FS=OFS="\t" 
        maxNF = (NF > maxNF ? NF : maxNF)            # keep track of max number of columns
         for (i=1; i<=NF; i++) 
             if ( $i == "" )                          # ignore empty cell
                continue
             for (j=1; j<=ndx[i]; j++)               # loop through values already seen for this column
                 if ( $i == vals[i][j] )             # and if already seen then
                    $i = ""                           # clear the current cell and
                    break                             # break out of this for/testing loop
                 
             
             if ( $i != "" )                         # if we got this var and the cell is not empty then 
                vals[i][++ndx[i]] = $i                # store the new value in our array
             
         
       
END     for (j=1; j<=NR; j++)                       # loop through all possible rows
             pfx = ""
             for (i=1; i<=maxNF; i++)                # loop through all possible columns
                 printf "%s%s", pfx, vals[i][j]       # non-existent array entries default to ""
                 pfx = OFS
             
             printf "\n"
         
       
' input_file

注意:数组结构(arr[i][j])需要GNU awk,否则我们可以转换为arr[i,j]的伪双索引数组结构

这会生成:

C1      C2      C3      C4      C5      C6      C7
111     111     222     333     111     222     777
222     444     333     111     222     333     666
333     666     444     222     333     555     555
444     777     555     777     444     666     444
777     888     777     555     555     888     333
999             999     666     666
                                888

【讨论】:

以上是关于从文本文件中删除每个单独列中的重复项的主要内容,如果未能解决你的问题,请参考以下文章

将每个 excel 列数据保存到单独的文本文件中

从 Pandas Dataframe Column 中删除重复的逗号,换句话说,我只需要列中的文本,用逗号分隔它们

SQL查询从特定列中的每个字段中删除某些文本 - Oracle SQL

删除重复的数组条目

从熊猫列中删除列表中的单词 - python 2.7

网格列中的 XAML 拉伸文本块