这里的主要问题是您说“百万列”,并没有指定多少行。为了检查每一行中的每个值与其他列中的对应值..您正在查看大量检查。
当然,您可以在执行过程中减少列数,但您仍需要逐一检查直到最后一行。如此...大量处理。
我们可以从前两行开始创建一个“种子”哈希:
use strict;
use warnings;
open my $fh, '<', "inputfile.txt" or die;
my %matches;
my $line = <$fh>;
my $nextline = <$fh>;
my $i=0;
while ($line =~ s/\t(\d+)//) {
my $num1 = $1;
if ($nextline =~ s/\t(\d+)//) {
if ($1 == $num1) { $matches{$i} = $num1 }
} else {
die "Mismatched line at line $.";
}
$i++;
}
然后使用这个“种子”哈希,您可以读取其余行,并从哈希中删除不匹配的值,例如:
while($line = <$fh>) {
my $i = 0;
while ($line =~ s/\t(\d+)//) {
if (defined $matches{$i}) {
$matches{$i} = undef if ($matches{$i} != $1);
}
$i++;
}
}
您可以想象一种解决方案,即剥离所有已被证明是唯一的行,但为了做到这一点,您需要制作该行的数组,或者制作一个正则表达式,我不确定这不会像简单地通过字符串一样长。
然后,在处理完所有行之后,您将得到一个包含重复数字值的哈希值,因此您可以重新打开文件并进行打印:
open my $fh, '<', "inputfile.txt" or die;
open my $outfile, '>', "outfile.txt" or die;
while ($line = <$fh>) {
my $i = 0;
if ($line =~ s/^([^\t]+)(?=\t)//) {
print $outfile $1;
} else { warn "Missing header at line $.\n"; }
while ($line =~ s/(\t\d+)//) {
if (defined $matches{$i}) { print $1 }
$i++;
}
print "\n";
}
这是一个相当繁重的操作,并且此代码未经测试。这将为您提供解决方案的提示,处理整个文件可能需要一段时间。我建议运行一些测试以查看它是否适用于您的数据,然后对其进行调整。
如果您只有几个匹配的列,则简单地从行中提取它们要容易得多,但我不愿在这么长的行上使用 split。比如:
while ($line = <$fh>) {
my @line = split /\t/, $line;
for my $key (sort { $b <=> $a } keys %matches) {
splice @line, $key + 1, 1;
}
$line = join ("\t", @line);
$line =~ s/\n*$/\n/; # awkward way to make sure to get a single newline
print $outfile $line;
}
请注意,我们必须按数字降序对键进行排序,以便我们从末尾修剪值。否则我们会搞砸后续数组编号的唯一性。
无论如何,这可能是一种方法。不过,这是一个相当大的操作。我会保留备份。 ;)