在Perl中匹配数组元素最有效的过程?

时间:2014-10-29 14:51:31

标签: arrays performance perl element matching

我有两个数组(Array1和Array2)。 Array1包含大约20,000个非唯一元素。 Array2包含大约90,000个唯一元素。我试图计算Array1中的元素数量,这些元素也显示为Array2的元素。下面的perl脚本成功但缓慢。是否有另一种方法可以计算Array2中存在的可能比这更快的Array1元素的数量?

#!/usr/bin/perl
use strict;
use warnings;
use autodie;

# This program counts the total number of elements in one array that exist in a separate array.

my $Original_Array_File = "U:/Perl/MasterArray.txt";

# Read in the master file into an array.
open my $file, '<', $Original_Array_File or die $!;
my @Array2 = <$file>;
close $file;

my $path = "C:/Files by Year/1993";
chdir($path) or die "Cant chdir to $path $!";

for my $new_file ( grep -f, glob('*.txt') ) {
    open my ($new_fh), '<', $new_file;
    my @Array1 = <$new_file>;
    my @matched_array_count ;

    foreach @Array1 {
         ++$matched_array_count if ($_ ~~ @Array2 ) ;                            
         } 

2 个答案:

答案 0 :(得分:4)

性能问题的主要来源是:

foreach @Array1 {
    ++$matched_array_count if ($_ ~~ @Array2 );                            
} 

根据smartmatch documentation

的行为
$string ~~ @array

就像

grep { $string ~~ $_ } @array

$string1 ~~ $string2

就像

$string1 eq $string2

将这些内容与原始代码段放在一起,我们得到类似的内容:

foreach my $string1 @Array1 {
    ++$matched_array_count if grep { $string1 eq $_ } @Array2;
}

换句话说,取@Array1中的第一个元素并将其与@Array2中的每个元素进行比较,然后取@Array1中的第二个元素,将其与@Array2中的每个元素进行比较,依此类推。这可以解决

scalar @Array1 * scalar @Array2

比较,总计大约18亿。

通常在Perl中完成的方式是使用哈希。单个散列查找比搜索数组中的每个元素要快得多。基本算法是:

  1. 将您的“haystack”(您在中搜索的)加载到哈希中。
  2. 遍历您的“针头”(您正在搜索 的内容)并使用exists查看哈希中是否有匹配的密钥。
  3. 在您的特定情况下,您可以将U:/Perl/MasterArray.txt的内容加载到哈希中,然后执行

    scalar @Array1
    

    哈希查找,或~2,000。这将比现在快得多。

    以下是在Linux词典文件中搜索单词的示例:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use 5.010;
    
    my $file = '/usr/share/dict/linux.words';
    open my $fh, '<', $file or die "Failed to open '$file': $!";
    
    my %haystack = map { chomp; $_ => 1 } <$fh>;
    
    my $count;
    while (<DATA>) {
        chomp;
        $count++ if exists $haystack{$_};
    }
    
    say $count;
    
    __DATA__
    foo
    bar
    foobar
    fubar
    

    输出:

    3
    

    (显然,“foobar”是一个单词。“FUBAR”是一个单词,但小写的“fubar”不是。)

    Smartmatch是实验性的

    您还应该知道,从Perl 5.18.0开始,the smartmatch family of features are now experimental

      

    智能匹配,在v5.10.0中添加并在v5.10.1中进行了重大修订,一直是一个常规投诉点。尽管有许多方法可用,但它也证明了Perl的用户和实现者都存在问题和困惑。关于如何最好地解决问题,已经提出了许多建议。 很明显,smartmatch几乎肯定会在将来改变或消失。不建议依赖其当前行为。 (强调添加)

答案 1 :(得分:0)

看起来你想比较很多文件。

您可以将其拆分为使用每个文件一个线程的线程池。或者,如果您受到更多内存限制,则可以将其中一个数组拆分为多个部分,并将每个部分发送到不同的线程。