【问题标题】:Efficient use of Perl hash高效使用 Perl 哈希
【发布时间】:2016-02-18 02:21:38
【问题描述】:

我正在使用哈希来缩写州名

%STATEABBRIVATE = ('ALABAMA' => 'AL',
                   ...);

我的一些输入集已经有缩写的州名。使用if defined $STATEABBRIVATE{$state} 还是将另外51 个匹配对'AL'=>'AL' 添加到哈希中会更有效吗?

【问题讨论】:

  • 如果你想验证状态是否真的存在,使用AL => 'AL'可能是最简单的方法。
  • $state = $STATEABBRIVATE{$state} if length($state) > 2
  • 如果问题是关于性能的,答案是:没关系。 (任何差异都可以忽略不计/不明显。)
  • 当然,您可以通过不基于某些条件(例如字符串长度 == 2)进行映射来节省几个周期。但是对所有值进行映射允许验证。由于散列长度是有限的(100 个值),查找将非常有效。不验证输入以避免查找哈希键对我来说似乎是过早的优化。
  • “过早的优化是万恶之源”。不要投机优化。编写清楚它在做什么的代码。如果需要优化,请运行分析器。很有可能,不会有 - 现在计算机速度非常快,因此对于大多数数据集,您不会节省大量时间。 (如果有的话,一旦你优化了它,然后在 6 个月的时间里实现你就不再理解它了)

标签: performance perl hash


【解决方案1】:

如果您想验证状态是否真的存在,使用AL => 'AL' 可能是最简单的方法。

要保持代码干燥(不要重复自己),您可以

my %STATEABBRIVATE = ( ALABAMA => 'AL',
                       ...
                     );
my @abbrevs = values %STATEABBRIVATE;
@STATEABBRIVATE{@abbrevs} = @abbrevs;

如果您关心性能,瓶颈可能在其他地方:

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

use Benchmark qw{ cmpthese };
use Test::More;

my %hash = qw( Alabama AL Alaska AK Arizona AZ Arkansas AR California CA
               Colorado CO Connecticut CT Delaware DE Florida FL
               Georgia GA Hawaii HI Idaho ID Illinois IL Indiana IN
               Iowa IA Kansas KS Kentucky KY Louisiana LA Maine ME
               Maryland MD Massachusetts MA Michigan MI Minnesota MN
               Mississippi MS Missouri MO Montana MT Nebraska NE
               Nevada NV Ohio OH Oklahoma OK Oregon OR Pennsylvania PA
               Tennessee TN Texas TX Utah UT Vermont VT Virginia VA
               Washington WA Wisconsin WI Wyoming WY );

$hash{'West Virginia'}  = 'WV';
$hash{'South Dakota'}   = 'SD';
$hash{'South Carolina'} = 'SC';
$hash{'Rhode Island'}   = 'RI';
$hash{'North Dakota'}   = 'ND';
$hash{'North Carolina'} = 'NC';
$hash{'New York'}       = 'NY';
$hash{'New Mexico'}     = 'NM';
$hash{'New Jersey'}     = 'NJ';
$hash{'New Hampshire'}  = 'NH';

my %larger = %hash;
@larger{ values %hash } = values %hash;

sub def {
    my $state = shift;
    return defined $hash{$state} ? $hash{$state} : $state
}

sub ex {
    my $state = shift;
    return exists $hash{$state} ? $hash{$state} : $state
}

sub hash {
    my $state = shift;
    return $larger{$state}
}

is(def($_), ex($_),   "def-ex-$_")   for keys %larger;
is(def($_), hash($_), "def-hash-$_") for keys %larger;

done_testing();

cmpthese(-1,
         { hash => sub { map hash($_), keys %larger },
           ex   => sub { map ex($_),   keys %larger },
           def  => sub { map def($_),  keys %larger },
         });

结果:

        Rate  def   ex hash
def  27307/s   --  -2% -11%
ex   27926/s   2%   --  -9%
hash 30632/s  12%  10%   --

【讨论】:

  • 简单的实现让我第二次猜测解决方案的效率。
  • @MattJacob:没有看到代码,只能猜测。
【解决方案2】:

if defined $STATEABBRIVATE{$state} 和任何哈希查找都将是常数时间(即 O(1) 操作)。事实上,defined() 可能无论如何都在幕后使用哈希表查找。因此,我的预测是,即使使用大型数据集,性能上的差异也可以忽略不计。这充其量只是一个有根据的猜测。

【讨论】:

    猜你喜欢
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 2015-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多