什么是使用哈希引用的最佳方式?

时间:2013-04-01 05:51:06

标签: arrays performance perl hash reference

我正在研究一个生成多个大型哈希数组(HoAs)数据结构的脚本。我正在尝试优化我的脚本,因为它目前需要花费大量时间才能运行。

我做了一些基准测试。我设法使脚本执行约。通过直接使用@_而不是将其复制到变量中,利用数组引用和减少子程序调用开销,可以快3.5倍。我还删除了不必要的子程序和冗余变量声明。尽管有这些改进,我还是想让代码运行得更快。

在我的脚本开始时,我解析一个大文件以生成两个HoA数据结构。 关于哈希引用的这些方法中哪一种最可行和最有效? HoA看起来像这样:

%HoA = (
    'C1' =>  ['1', '3', '3', '3'],
    'C2' => ['3','2'],
    'C3' => ['1','3','3','4','5','5'],
    'C4'  => ['3','3','4'],
    'C5' => ['1'],
);

选项1

解析文件时生成HoAs(见下文)。最后将数组的哈希值放入哈希引用。

my $hash_ref = \%HoA;

选项2

解析文件,使HoA中的每个键都有一个指向array_ref的值。最后将数组的哈希值放入哈希引用。

==============

我觉得选择2是一个很好的方法,但我该怎么做?

以下是我目前正在做的事情。

use strict; use warnings;
open(F1, "file.txt") or die $!;
my %HoA = ();
    while (<F1>){
    $_=~ s/\r//;
    chomp;
    my @cols = split(/\t/, $_);

    push( @{$HoA{$cols[0]}}, @cols[1..$#cols]);
 }
close F1;

我需要一个高效的数据结构,这将有助于我快速查找值和键。此外,我需要能够将键值(数组),键和HoA本身尽可能高效地传递到子程序中。

4 个答案:

答案 0 :(得分:4)

  • 不要使用全局变量,包括文件句柄。
  • 您宣布%HoA并且从未使用过。
  • 您宣布$HoA_ref并且从未使用过它。
  • 您使用了$HoA而没有声明它。始终使用use strict; use warnings;
  • 为什么要创建一个您不需要的引用并最终多次取消引用它?
  • 没有理由为您刚创建的哈希分配空列表。 my %HoA = ();很愚蠢。
  • 可能会合并s///chomp;
  • 在不需要时省略$_,或使用有意义的变量名称。

以上所有以及其他一些改进措施都是为了获得:

use strict;
use warnings;

open(my $fh, '<', 'file.txt') or die $!;

my %HoA;
while (<$fh>){
    s/\r?\n\z//;
    my ($key, @cols) = split /\t/;
    push @{ $HoA{$key} }, @cols;
}

答案 1 :(得分:2)

我的经验是,尽可能使用参考资料是最好的。一些补充说明:

  1. 如果你需要这个,$_=~ s/\r//;用于Windows eol兼容性,那么你需要一个更好的perl构建。 ActiveState通常是最强大的。 chomp应该处理终端cr / lf,或者更确切地说读取的文件应该已经将cr / lf对转换为lf。

  2. Perl shift是O(1)并且非常快。你可以在这里利用这个优势。

  3. 你不能事先告诉你什么是最快的。选项基准是唯一的出路。

  4. 尝试单独阅读输入文件而不进行处理。一旦作业受I / O限制,优化就不再有用了。

  5. 以下是我的开始:

     open(F, "file.txt") or die $!;
     my $h = {};
     while (<F>){
       chomp;
       my @cols = split "\t";
       my $key = shift @cols;
       push @{$h->{$key}}, @cols;
     }
     close F;
    

答案 2 :(得分:1)

我认为这是你在你的例子中尝试做的事情。

open(my $fh, "<", "file.txt") or die $!;
my $HoA_ref = {}; # ref will return a HASH 
while (my $line = <$fh>) {
    $line =~ s/\r//;
    chomp $line;
    my @cols = split(/\t/, $line);

    # shift off first element in the list to use 
    # as the key
    my $key = shift(@cols);
    # set value to an array ref of whatever 
    # is left in the list.
    $HoA_ref->{$key} => [@cols];
}
close <$fh>;

值得注意的是,$key如果在循环浏览文件时出现不止一次,将会被覆盖。

答案 3 :(得分:1)

由于你有大文件,而不是使用while循环,我建议使用模块File::Slurp进行完整的文件诽谤。

File :: Slurp read_file函数尝试使用sysread(检查read_file source code)调用来绕过perl I / O.

my $text = read_file( $file ) ;