【问题标题】:Check and count duplicates lines检查并计算重复行
【发布时间】:2016-09-27 23:28:42
【问题描述】:

我有一个输入数据,例如:

chr17   41243232    41243373    BRCA1_ex11
chr17   41243232    41243373    BRCA1_ex12
chr17   41243471    41243644    BRCA1_ex11
chr17   41243639    41243811    BRCA1_ex11
chr13   32954112    32954208    BRCA2_ex23
chr13   32954112    32954208    BRCA2_ex24

我需要检查重复行$2$3行,如果重复,我需要合并成一行,$4列打印为逗号分隔。

输出:

chr17   41243232    41243373    BRCA1_ex11,BRCA1_ex12
chr17   41243471    41243644    BRCA1_ex11
chr17   41243639    41243811    BRCA1_ex11
chr13   32954112    32954208    BRCA2_ex23,BRCA2_ex24

是否有任何 AWK 解决方案可以轻松处理此类数据?我将不胜感激解释的解决方案。输入和输出是制表符分隔的格式。注意:第一个、第二个和第三个字段是相等的。

我的尝试是:

awk -v OFS="\t" '{i=$2 FS $1 FS $3 FS $4} {a[i]=!a[i]?$4:a[i] "," $4} END {for (l in a) {print l,a[l]}}' infile

感谢您的任何想法。

【问题讨论】:

  • 如果第一个字段不同而第二个和第三个字段相等怎么办?你有没有自己尝试过什么?
  • @JamesBrown 谢谢你的好问题。第一个字段与第二个和第三个字段相同。是的,我试图在 awk 中排列数组 - 但仍在自学。我将编辑我的帖子..

标签: bash awk sed duplicates


【解决方案1】:
$ cat script.awk
{
    a[$2 OFS $3] = $1                  # store $1, last instance
    b[$2 OFS $3] = b[$2 FS $3] $4 ","  # append the $4s
} 
END {
    for (i in a) {                     # order is awk default
        sub(/,$/, "", b[i])            # remove trailing ","
        print a[i], i, b[i]            # print
    }
}

运行:

$ awk -f script.awk infile
chr17 41243471 41243644 BRCA1_ex11
chr17 41243232 41243373 BRCA1_ex11,BRCA1_ex12
chr17 41243639 41243811 BRCA1_ex11
chr13 32954112 32954208 BRCA2_ex23,BRCA2_ex24

【讨论】:

  • 看起来这很好用。詹姆斯,你有解决方案,谢谢。
【解决方案2】:

只需将第一个作业替换为

 i=$1 FS $2 FS $3

并可能通过sed 过滤输出以用制表符替换空格:

...  | sed 's/ /    /g'

      space---^   ^--- TAB

输出:

chr13   32954112        32954208        BRCA2_ex23,BRCA2_ex24
chr17   41243639        41243811        BRCA1_ex11
chr17   41243232        41243373        BRCA1_ex11,BRCA1_ex12
chr17   41243471        41243644        BRCA1_ex11

【讨论】:

    【解决方案3】:

    如果perl 没问题:

    $ cat ip.txt 
    chr17   41243232    41243373    BRCA1_ex11
    chr17   41243232    41243373    BRCA1_ex12
    chr17   41243471    41243644    BRCA1_ex11
    chr17   41243639    41243811    BRCA1_ex11
    chr13   32954112    32954208    BRCA2_ex23
    chr13   32954112    32954208    BRCA2_ex24
    
    $ perl -ale '$k = join "\t",@F[0..2]; $h{$k} .= $h{$k} ? ",$F[3]" : $F[3]; END{ print "$_\t$h{$_}" foreach (keys %h) }' ip.txt 
    chr17   41243639    41243811    BRCA1_ex11
    chr17   41243232    41243373    BRCA1_ex11,BRCA1_ex12
    chr17   41243471    41243644    BRCA1_ex11
    chr13   32954112    32954208    BRCA2_ex23,BRCA2_ex24
    
    • -ale 在空格上拆分输入行并保存到 @F 数组,从输入行中去除换行符并为打印语句添加换行符
    • $k = join "\t",@F[0..2] 使用的键 - 前 3 个元素由 tab 加入
    • $h{$k} .= $h{$k} ? ",$F[3]" : $F[3] 将值附加到哈希变量,添加 , 取决于现有值是否为空
    • END{ print "$_\t$h{$_}" foreach (keys %h) } 处理完所有行后,打印由tab 分隔的键和值。键的顺序是随机的

    使用正则表达式提取键、值的替代方法:

    $ perl -nle '($k,$v)=/^(.*?)\s+(\S+)$/; $h{$k} .= $h{$k} ? ",$v" : $v; END{print "$_\t$h{$_}" foreach (keys %h) }' ip.txt 
    chr13   32954112    32954208    BRCA2_ex23,BRCA2_ex24
    chr17   41243639    41243811    BRCA1_ex11
    chr17   41243232    41243373    BRCA1_ex11,BRCA1_ex12
    chr17   41243471    41243644    BRCA1_ex11
    

    【讨论】:

      【解决方案4】:
      $ cat tst.awk
      {
          curr = $2 FS $3
      
          if (curr == prev) {
              buf = buf "," $NF
          }
          else {
              if (NR>1) {
                  print buf
              }
              buf = $0
          }
      
          prev = curr
      }
      END { print buf }
      
      $ awk -f tst.awk file
      chr17   41243232    41243373    BRCA1_ex11,BRCA1_ex12
      chr17   41243471    41243644    BRCA1_ex11
      chr17   41243639    41243811    BRCA1_ex11
      chr13   32954112    32954208    BRCA2_ex23,BRCA2_ex24
      

      这个和@JamesBrown's solution的区别是:

      1. 这一次只在内存中存储 1 个输出行,而 James 存储整个文件。
      2. 这将按照它们在输入中出现的顺序打印这些行,而 James 将按照“随机”(散列)顺序打印它们。
      3. 这依赖于您在示例中显示的键($2 和 $3)值是连续的输入,而 James 将按任何顺序输入。

      【讨论】:

        猜你喜欢
        • 2019-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-06
        • 1970-01-01
        • 1970-01-01
        • 2014-11-17
        • 2014-10-14
        相关资源
        最近更新 更多