我有一个标签分隔的大文件,如下所示:
input.txt中
a b c
s t e
a b c
f q y
r e x
删除此文件中的重复行(行),我使用:
my %seen;
my @lines;
while (<>) {
my @cols = split /\s+/;
unless ($seen{$cols[0]}++) {
push @lines, $_;
}
}
print @lines;
这里的输出是:
a b c
s t e
f q y
r e x
现在,如果我想要删除包含重复值的那些行(意味着:该值一旦出现在上行/列中的任何位置,此处为“e”)并且仅保留包含行的最高值,请建议将是什么最常用的方法是记住我的输入文件非常大,有很多列和行。
我想要的上述input.txt的模型输出将是:
a b c
s t e
f q y
谢谢
答案 0 :(得分:4)
您还需要遍历@cols
并检查每个项目,而不仅仅是第一个项目$cols[0]
。
你需要像
unless ($seen{$cols[0]}++ || $seen{$cols[1]}++ || $seen{$cols[2]}++ ...) {
push @lines, $_;
}
当然,如果您事先不知道列数,这将是糟糕的风格,不可能。
我会用grep
:
my %seen;
my @lines;
while (<DATA>) {
my @cols = split /\s+/;
unless ( grep { $seen{$_}++ } @cols ) {
push @lines, $_;
}
}
print @lines;
__DATA__
a b c
s t e
a b c
f q y
r e x
输出:
a b c
s t e
f q y
grep
处理列表{ $seen{$_}++ }
中每个元素的curlies @cols
之间的代码,并返回(在标量上下文中)评估为true的项目数。
这不是最快的方法,因为它总是迭代整个数组(即使第一次评估对于您的特定测试也是如此)。但试一试;或许这对你来说足够快。
答案 1 :(得分:2)
正如我在评论中写的那样,split /\s+/
很少是正确的
您使用重复字段错误处理行的解决方案
使用核心grep
模块中的any
替换List::Util
也更有效率
我建议您将每行的字段存储在哈希%cols
中,就像这样
use strict;
use warnings 'all';
use List::Util 'any';
my ( @lines, %seen );
while ( <DATA> ) {
my %cols = map { $_ => 1 } split;
push @lines, $_ unless any { $seen{$_}++ } keys %cols;
}
print for @lines;
__DATA__
a b c
p p p
p q r
s t e
a b c
f q y
r e x
a b c
p p p
s t e
即使这可能不是您想要的,因为省略了f q y
行,因为q
已经被&#34;看到&#34;在省略的行p q r
中。在这种情况下,您必须澄清所需的行为