如何在txt文件中查找单个条目?

时间:2013-07-10 11:59:40

标签: perl awk duplicates unique uniq

我有一个包含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循环,但鉴于我有大约1.5M的条目,它可能需要一些时间。

5 个答案:

答案 0 :(得分:4)

尝试这个awk one-liner:

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

答案 1 :(得分:3)

这是另一种方式:

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 

答案 2 :(得分:2)

不是单行,但是这个小的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"; 
}

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:0)

我知道必须有perl单行回复。这是 - 没有经过严格测试,所以警告经纪人; - )

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上运行。当有几十个具有唯一第一列的类似记录时,它可以工作,并且在检查唯一行之前不需要对输入进行排序。约瑟夫·霍尔,约翰·麦克亚当斯和Effective Perl Programming(一本很棒的书 - 当智能匹配~~和{{}时,解决方案主要来自brian d foy末尾附近的单线示例。 1}}尘埃落定我希望出现新版本):

以下是(我认为)它如何运作:

  • 由于我们正在使用given when,因此我们免费获取-a数组,因此使用它而不是拆分
  • 因为我们正在使用@F我们在-n循环中,所以while() {} push的元素作为@F作为匿名参考数组(@AoA充当"anonymous array constructor")。那样他们就会闲逛,我们可以在以后再引用它们(这是否有意义?)
  • 使用上述图书中的[]惯用语(我们使用$seen{$_}++代替$S),@Axeman here on SO对{{3}}的独特元素进行了详细描述{1}}并根据我们看到具有给定值(行内容)的元素(或行)的次数,在$seen哈希中设置/增加键。
  • 使用“butterfly”@F[0]来突破%S然后,在一个单独的块中,我们使用两个}{循环来遍历外部数组并检查每个元素(它们本身就是匿名数组while - 每行一个),然后,对于每个内部匿名数组,for哪些值与$i一起在{{{1}中等于“{我们之前创建的哈希(grep或内部循环)并连续将这些值放在keys中。
  • 最后,我们遍历外部数组并打印任何匿名数组,其中该数组的第一个元素等于每个(%S)的值。我们这样做:(for $j (grep {$S{$_}==1} keys %S))。
@Kent手中的

$j有点精辟。如果有人有关于如何缩短或记录我的“线路噪音”的建议(我从未说过$j!)请添加建设性意见!

感谢阅读。