Arrays 如何使用Perl更高效地处理大型文本文件
问题: 我需要搜索一个巨大的文本文件(包含大约150万行数据),提取与唯一ID匹配的行。我将唯一ID存储在一个数组中,并在每个数组元素中遍历整个文件一次 虽然这种方法适用于小型阵列,但如果阵列相当大,它会大大降低我的程序的速度,因为要执行的操作太多了 我的数组最多可以包含10000个唯一标识符,其形式如下:Arrays 如何使用Perl更高效地处理大型文本文件,arrays,perl,Arrays,Perl,问题: 我需要搜索一个巨大的文本文件(包含大约150万行数据),提取与唯一ID匹配的行。我将唯一ID存储在一个数组中,并在每个数组元素中遍历整个文件一次 虽然这种方法适用于小型阵列,但如果阵列相当大,它会大大降低我的程序的速度,因为要执行的操作太多了 我的数组最多可以包含10000个唯一标识符,其形式如下: DC888U1 DC888U2 DC888U3 ... ... 数据文件中的行始终以唯一标识符开头 DC888U1苹果0.99 75 DC888U2橙子0.75 1002 DC888U3
DC888U1
DC888U2
DC888U3
...
...
数据文件中的行始终以唯一标识符开头
DC888U1苹果0.99 75
DC888U2橙子0.75 1002
DC888U3面包1.35 100
... ... ... ...
... ... ... ...
我的代码如下:
#array containing identifiers
open (IDENTIFIERS "< keywords.txt") or die "Cannot open file: $!";
chomp(my @keywords = <IDENTIFIERS>);
close (IDENTIFIERS);
#iterate through the array element by element
foreach my $element (@keywords) {
open (FH "< inventory.txt") or die "cannot open file: $!";
while (<FH>) {
if ($_ =~ /^\Q$element\E/) {
print $_;
}
}
close (FH);
}
包含标识符的数组
打开(标识符“有吗 关键是将O(N*M)代码转换为O(N+M):
使用严格;
使用警告;
使用v5.10;#汽车模具
使用自动模具;
die您要求进行优化,这在很大程度上取决于上下文
如果您对文件进行了排序(“排序”实际上意味着“根据您自己的标准进行排序”),您可以决定浪费一些磁盘空间,并创建一个新文件,其中包含填充为具有相同长度的相同行
然后对该文件使用二进制搜索,以获取所查找标识符的至少一个匹配项的行号(这就是为什么需要相同的行长,否则对该文件的搜索将无法正常工作)
如果标识符在文件中是唯一的,那么就完成了。
如果不是,则只需上移一行,直到标识符发生变化,然后下移一行,直到标识符发生变化,并获得间隔
再次强调:这只在文件被排序并且行的长度都相同的情况下才有效,但是如果是这样的话,那么您将看到速度的巨大提高。我知道,因为我自己这样做是为了在一个200Mb+的文本文件中搜索:)对于最常见的行长度,150万行数据并不是一个巨大的数据量。如果每条线都是1K,那么就有1.5GB的数据,即使在我十年前的笔记本电脑上,这些数据也可以整齐地存储在内存中
您的问题是由于您对每个标识符反复处理文件
因此,如果您有10000个标识符,并且处理该文件需要1秒,那么您的处理仍然需要3小时。如果处理该文件需要一分钟,则您的方法将需要7天
将10000个标识符作为密钥放入散列。然后,在遍历文件时,捕获每行上非空格字符的初始序列,检查它是否是散列中的键;如果是,请打印
未经测试:
my %keywords = map { $_ => undef } @keywords;
while (my $line = <$in>) {
my ($id) = ($line =~ /^(\S+)/);
if (exists $keywords{$id}) {
print $line;
}
}
my%keywords=map{$\=>unde}@keywords;
while(我的$line=){
我的($id)=($line=~/^(\S+/);
if(存在$keywords{$id}){
打印$行;
}
}
除非您处理正则表达式没有的情况,否则^
锚定是没有意义的match@Borodin我写下我的意思。如果标识符应该在行的开头,我就这样写。答案的要点是避免重复读取文件。。。OP可以处理其余部分,这取决于数据行上是否允许前导空格。@Borodin:perl-E'my$re=“aa | bb”$re=qr/$re/;说“不,不,博罗丁。”除非“abb”=~/^$re/'
my %keywords;
{
my $keywords_file = shift;
open my $fh, '<', $keywords_file;
@keywords{ map s/\s//gr, <$fh> } = (); #/ make syntax highlight happy
};
while (<>) { print if /^(\S+)/ and exists $keywords{$1} }
my %keywords = map { $_ => undef } @keywords;
while (my $line = <$in>) {
my ($id) = ($line =~ /^(\S+)/);
if (exists $keywords{$id}) {
print $line;
}
}