【问题标题】:How to only print lines with unique fields?如何仅打印具有唯一字段的行?
【发布时间】:2011-09-29 19:06:38
【问题描述】:

例如...如果我有这样的文件:

A   16  chr11   36595888
A   0   chr1    155517200
B   16  chr1    43227072
C   0   chr20   55648508
D   0   chr2    52375454
D   16  chr2    73574214
D   0   chr3    93549403
E   16  chr3    3315671

我只需要打印具有唯一第一列的行:

B   16  chr1    43227072
C   0   chr20   55648508
E   16  chr3    3315671

类似于awk '!_[$1]++',但我想删除所有具有非唯一拳头字段的行。

最好是 Bash 和 python 解决方案。

【问题讨论】:

  • 总是按第一列排序吗?
  • 第一列的值是否有固定范围?如果有,范围是多少?

标签: python bash unique


【解决方案1】:

在 bash 中,假设第一列已用 (3) 固定:

sort input-file.txt | uniq -u -w 3

'-u' 选项只打印唯一的行,'-w 3' 比较不超过前 3 个字符。

【讨论】:

  • 它确实非常快且内存效率很高,但我没有提到真实数据具有可变数量的字符......但我可以使用awk '{print $0, "\t", $1}' file |sort | uniq -u -f 4谢谢你的行!
【解决方案2】:

这个怎么样:

#!/usr/bin/env python
from collections import defaultdict
data = defaultdict(list)
with open('file', 'rb') as f:
    for line in sorted(f.readlines()):
        data[line[0]].append(line)
for key in sorted(data.iterkeys()):
    if len(data[key]) == 1:
        print data[key]

【讨论】:

    【解决方案3】:
    awk '
      {count[$1]++; line[$1]=$0}
      END {for (val in count) if (count[val]==1) print line[val]}
    ' filename
    

    这可能会改变行的顺序。如果这是个问题,试试这个 2-pass 方法:

    awk '
      NR==FNR {count[$1]++; next}
      count[$1] == 1 {print}
    ' filename filename
    

    【讨论】:

      【解决方案4】:

      sed 一个班轮解决方案:

      sed ':a;$bb;N;/^\(.\).*\n\1[^\n]*$/ba;:b;s/^\(.\).*\n\1[^\n]*\n*//;ta;/./P;D' file
      

      【讨论】:

        【解决方案5】:

        在 python 中,更容易阅读和调整:

        d = dict()
        for line in open('input-file.txt', 'r'):
          key = line.split(' ', 1)[0]
          d.setdefault(key, list()).append(line.rstrip())
        
        for k, v in sorted(d.items()):
          if len(v) == 1:
             print v[0]
        

        【讨论】:

          【解决方案6】:
          import sys
          from collections import OrderedDict
          lines = OrderedDict()
          for line in sys.stdin:
              field0 = line.strip().split('\t')[0]
              lines[field0] = None if field0 in lines else line
          for line in lines.values():
              if line is not None:
                  sys.stdout.write(line)
          

          如果您不关心保留顺序,您可以使用普通的旧字典 ({}) 而不是 OrderedDict

          此实现不关心重复字段是否相邻。

          【讨论】:

            猜你喜欢
            • 2015-01-08
            • 2014-07-07
            • 2019-08-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多