【问题标题】:How to find single entries in a txt file?如何在txt文件中查找单个条目?
【发布时间】:2013-07-10 11:59:40
【问题描述】:

我有一个 12 列的 txt 文件。有些行是重复的,有些则不是。例如,我复制到数据的前 4 列。

0       0       chr12   48548073  
0       0       chr13   80612840
2       0       chrX    4000600 
2       0       chrX    31882528 
3       0       chrX    3468481 
4       0       chrX    31882726
4       0       chr3    75007624

根据第一列,您可以看到除了条目 '3' 之外还有一些重复项。 我想打印唯一的单个条目,在本例中为“3”。

输出将是

3       0       chrX    3468481

有没有使用 awk 或 perl 的快速方法?我只能考虑在 perl 中使用 for 循环,但考虑到我有大约 150 万个条目,这可能需要一些时间。

【问题讨论】:

  • 总是 12 列?仅基于第一列或所有行的比较?
  • 它总是 12 列,是的,比较应该只基于第一列。但是一旦找到单个条目,我想打印所有列。

标签: perl awk duplicates unique uniq


【解决方案1】:

试试这个 awk 单行:

awk '{a[$1]++;b[$1]=$0}END{for(x in a)if(a[x]==1)print b[x]}' file

【讨论】:

  • @JS웃 不,我不是,我的机器很快。 ;)
  • @user1007742 因为你有 150 万条记录要分析,我很想知道你能在这个 awk 和 || 之间进行任何比较uniq 方法和正确的 perl 脚本由 @Hunter McMillen 或我的 perl 单线进一步下方。我怀疑@Hunter 可能有最快的方法。
【解决方案2】:

这是另一种方式:

uniq -uw8 inputFile
  • -w8 将比较前 8 个字符(即您的第一列)的唯一性。
  • -u 选项将只打印出现一次的行。

测试:

$ cat file
0       0       chr12   48548073  
0       0       chr13   80612840
2       0       chrX    4000600 
2       0       chrX    31882528 
3       0       chrX    3468481 
4       0       chrX    31882726
4       0       chr3    75007624

$ uniq -uw8 file
3       0       chrX    3468481 

【讨论】:

    【解决方案3】:

    不是单行的,但这个小的 Perl 脚本完成了同样的任务:

    #!/usr/bin/perl
    use strict;
    use warnings FATAL => 'all';
    
    # get filehandle
    open( my $fh, '<', 'test.txt');
    
    # all lines from your file
    my %line_map; 
    
    while( my $line = <$fh> ) { # read a line
    
       my $key;
       my @values;
    
       # split on whitespace
       ($key, @values) = split(/\s+/, $line);
    
       # delete a line if it already exists in the map
       if( exists $line_map{$key} ) {
           delete $line_map{$key};
       } 
       else { # mark a line to show that it has been seen
          $line_map{$key} = join("\t", @values);
       }
    }
    
    # now the map should only contain non-duplicates
    for my $k ( keys %line_map ) {
       print "$k\t", $line_map{$k}, "\n"; 
    }
    

    【讨论】:

    • 很好,将大文件作为 %hash 读取时会很慢吗?它可以从Tie::File 中受益吗?我编造了一个perl 单线,它似乎工作。请参阅我的第二个答案。
    • 我认为这只有在非唯一行成对出现时才能正常工作。我相信用$line_map{$key} = undef; 替换delete $line_map{$key}; 并在next unless defined $line_map{$k} 循环的开头添加for 会起作用。
    【解决方案4】:

    无法正确格式化评论。 @JS웃 可能依赖于 GNU uniq ...这似乎适用于 BSD 派生版本:

    grep ^`cut -d" " -f1 col_data.txt  | uniq -u` file.txt
    

    必须有一个更短的perl 答案:-)

    【讨论】:

      【解决方案5】:

      我知道必须有一个perl 单行响应。在这里 - 没有经过大量测试,所以 caveat emptor ;-)

      perl -anE 'push @AoA,[@F]; $S{$_}++ for @F[0];}{for $i (0..$#AoA) {for $j (grep {$S{$_}==1} keys %S) {say "@{$AoA[$i]}" if @{$AoA[$i]}[0]==$j}}' data.txt
      

      这种方法的缺点是它以稍微修改的格式输出数据(我认为这很容易修复)并且它使用两个 for 循环和一个“蝴蝶运算符”(!!)它还使用grep()(它引入了一个隐式循环 - 即即使您不必自己编写循环也可以运行代码),因此它可能会很慢,有 150 万条记录。不过,我想看看它与 awkuniq 的比较。

      从好的方面来说,它不使用任何模块,应该可以在 Windows 和 OSX 上运行。当有几十个具有唯一第一列的类似记录并且不需要在检查唯一行之前对输入进行排序时,它就可以工作。该解决方案主要取自 Joseph Hall、Joh McAdams 和 brian d foyEffective Perl Programming 结尾附近的单行示例(一本很棒的书——当智能匹配 ~~given when 尘埃落定时,我希望新版本出现):

      这是(我认为)它的工作原理:

      • 由于我们使用的是-a,因此我们免费获得了@F 数组,因此使用它而不是拆分
      • 因为我们使用-n,所以我们在while() {} 循环内,所以push 的元素@F@AoA 作为匿名引用数组([] 充当@987654323 @)。这样他们就会到处闲逛,我们以后可以参考他们(这有意义吗???)
      • 使用上面提到的书中的$seen{$_}++ 成语(我们使用$S 而不是$seen)并由@Axeman here on SO 很好地描述,以查看@F[0] 的独特元素和设置/增量键我们的%S 哈希值根据我们看到具有给定值的元素(或行)的次数(行内容)。
      • 使用“蝴蝶”}{ 突破while 然后,在一个单独的块中,我们使用两个for 循环遍历外部数组并检查每个元素(它们本身就是匿名数组@ 987654349@ - 每行一个),然后,对于每个内部匿名数组,grepkeys 对应的值等于我们之前创建的 %S 哈希中的“1”(for $j (grep {$S{$_}==1} keys %S),或内循环)并将这些值连续放入$j
      • 最后,我们遍历外部数组并打印任何匿名数组,其中该数组的第一个元素等于每个数组的值 ($j)。我们通过以下方式做到这一点:(@{$AoA[$i]}[0]==$j)。

      @Kent 手中的awk 更简洁一些。如果有人对如何缩短或记录我的“线路噪音”有任何建议(我从来没有说过 perl!)请添加建设性的 cmets!

      感谢阅读。

      【讨论】:

      • 只翻译 awk 解决方案似乎更简单:perl -anE '$c{$F[0]}++; $l{$F[0]} = $_; END {say $l{$_} for grep {$c{$_} == 1} keys %c}' file
      • 好一个。我非常担心不会被uniq 行必须成对(要求它们首先是sort-ed)的情况所困扰,以至于我想这有点过分了。干杯。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多