Основная проблема здесь в том, что вы сказали «миллионы столбцов» и не указали, сколько строк. Чтобы проверить каждое значение в каждой строке по отношению к его аналогу в каждом другом столбце ... вы просматриваете множество проверок.
Конечно, вы сможете уменьшить количество столбцов по мере продвижения, но вам все равно придется проверять каждый столбец до последнего ряда. Итак ... большая обработка.
Мы можем создать начальный хеш с двух первых строк:
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;
}
Обратите внимание, что нам нужно отсортировать ключи в порядке убывания, чтобы мы обрезали значения с конца. В противном случае мы испортим уникальность последующих номеров массивов.
В любом случае, это может быть один из способов. Хотя это довольно большая операция. Я бы держал резервные копии. ;)