【问题标题】:remove entirely same duplicate columns in unix删除 unix 中完全相同的重复列
【发布时间】:2015-10-30 21:30:39
【问题描述】:

假设我有一个文件如下:

number 2 6 7 10 number 6 13  
name1 A B C D name1 B E   
name2 A B C D name2 B E  
name3 B A D A name3 A F  
name4 B A D A name4 A F  

我希望删除完全相同的重复列,输出文件如下:

number 2 6 7 10 13  
name1 A B C D E   
name2 A B C D E  
name3 B A D A F  
name4 B A D A F  

我对行使用sortuniq 命令,但从不知道如何对列执行操作。谁能推荐一个好方法?

【问题讨论】:

  • awk '{print $1, $2, $3, $4, $5, $7, $8}' file > file.new ? (注意缺少的 6 美元)。祝你好运。
  • @shellter:你不应该回答吗?
  • Java 答案是否可以接受,还是只能在 Linux 命令中使用?
  • 如果你已经知道公共列的索引,试试这个:awk '{$6="";$7="";print}' [filename]

标签: sorting unix awk


【解决方案1】:

这是一种保留顺序的 awk 方法

awk 'NR==1{for(i=1;i<=NF;i++)b[$i]++&&a[i]}{for(i in a)$i="";gsub(" +"," ")}1' file

输出

number 2 6 7 10 13  
name1 A B C D E   
name2 A B C D E  
name3 B A D A F  
name4 B A D A F  

工作原理

NR==1

如果是第一条记录

for(i=1;i<=NF;i++)

对字段进行循环,NF 是字段数

b[$i]++&&a[i]

如果$i(字段i中包含的数据)多次出现,则向数组a添加一个元素,键为i。

下一个块在所有记录上执行(包括记录一个)。

{for(i in a)$i="";

对于集合中的每个键,对应的字段为空。

gsub(" +"," ")

去掉多余的空格

1

总是计算结果为真,因此打印所有记录。

【讨论】:

    【解决方案2】:

    这个 Perl 单行代码可以解决问题:

    perl -an -e '@cols = grep { !$seen{$F[$_]}++ } 0..$#F unless @cols; print join " ", @F[@cols],"\n"' inputfile
    

    -ainputfile 的每一行拆分为@F。该文件的第一行用于从左到右构造列索引列表,只保留那些看不见的。接下来它打印@F 的切片,其中每行只包含这些列。

    【讨论】:

    • perl 新手。 $_ 是什么意思?
    • $_ 是默认变量。如果您从右到左阅读该语句:定义了unless @cols,对于从0@F 中的最后一个索引的每个值($_),测试哈希%seen 是否没有设置为$F[$_] 的值(并增加,以便再次看到测试失败),如果没有看到 grep$_ 中的索引传递给 @cols
    【解决方案3】:

    你可以使用awk:

    NR == 1 {
      for (ii = 1; ii <= NF; ii++) {
        cols[$ii] = ii
      }
      for (ii in cols) {
        printf "%s ", ii
      }
      print ""
    }
    
    NR > 1 {
      for (ii in cols) {
        printf "%s ", $cols[ii]
      }
      print ""
    }
    

    以上内容可能会重新排序列,但如有必要,可以通过更多努力来解决此问题。

    【讨论】:

      【解决方案4】:

      只需一个awk 命令即可删除重复行:

      awk '!a[$0]++'
      

      这会跟踪一行出现的次数。一旦出现一行,a[this row] 等于 1,所以当它再次出现时,a[this row] 已经为 True,而 ! 否定条件,因此不会打印。

      在您的情况下,您想删除重复的列。但是如何创建一个函数transpose 将行转换为列,反之亦然?

      我在回复Using bash to sort data horizontally时已经这样做了:

      transpose () {
        awk '{for (i=1; i<=NF; i++) a[i,NR]=$i; max=(max<NF?NF:max)}
              END {for (i=1; i<=max; i++)
                    {for (j=1; j<=NR; j++) 
                        printf "%s%s", a[i,j], (j<NR?OFS:ORS)
                    }
              }'
      }
      

      然后,它变得微不足道:

      $ cat file | transpose | awk '!a[$0]++' | transpose
      number 2 6 7 10 13
      name1 A B C D E
      name2 A B C D E
      name3 B A D A F
      name4 B A D A F
      

      【讨论】:

        猜你喜欢
        • 2021-06-01
        • 2020-07-27
        • 2017-12-11
        • 2020-11-29
        • 2014-03-10
        • 1970-01-01
        • 2023-01-17
        • 2013-08-02
        • 1970-01-01
        相关资源
        最近更新 更多