使用perl / linux计算特定列中的重复项

时间:2012-01-27 12:15:25

标签: linux perl

我有一个带有6列的文件(制表符分隔)(为简单起见,我在这里显示了2列)

46_#1   A   
47_#1   B   
49_#1   C   
51_#1   D   
51_#1   E

我想计算第一列中的重复项(仅计数 - 不删除)和下一列中的存储计数。所以输出应该是 -

46_#1   1  A    
47_#1   1  B    
49_#1   1  C    
51_#1   2  D    
51_#1   2  E

我使用过linux命令 -

uniq -c  file

但这将占整行(不是第一列),然后我使用

uniq -c -w5 file

但第一栏中的字数可能会有所不同。

有人可以帮忙吗?

PS-我有一个非常大的文件(大约1GB)。

2 个答案:

答案 0 :(得分:5)

我不喜欢提供完整的解决方案,但这似乎是最简单的解释方式。该程序读取文件两次:首先累加频率信息,然后输出修改后的数据。

use strict;
use warnings;

@ARGV or die "No input file specified";

open my $fh, '<', $ARGV[0] or die "Unable to open input file: $!";

my %count;

while (<$fh>) {
  next unless my ($key) = split;
  $count{$key}++;
}

seek $fh, 0, 0;
while (<$fh>) {
  chomp;
  next unless my ($key, $rest) = split ' ', $_, 2;
  print "$key $count{$key} $rest\n";
}

答案 1 :(得分:0)

假设文件已排序,您可以通过简单的命令来执行此操作:

sorin@sorin: $ join -1 1 -2 2 -o1.1,2.1,1.2 sample.txt <(cut -f1 sample.txt | uniq -c)
46_#1 1 A
47_#1 1 B
49_#1 1 C
51_#1 2 D
51_#1 2 E
  • join - 基于公共字段加入文件
    • -1 1 -2 2基于第一个文件的第一列和第二个文件的第二列
    • 进行连接
    • -o1.1,2.1,1.2选择要输出的列
    • <()进程替换 - 进程的输出转换为输入文件
    • join忽略uniq输出中的前导空格
  • cut - 仅提取一个字段

注意:如果文件没有排序,它可能更好地使用上一个答案,正如我从您的评论中看到的那样重复很远