سؤال

أحيانا أحيانا الوصول إلى التجزئة مثل هذا:

if(exists $ids{$name}){
    $id = $ids{$name};
}

هل هذه ممارسة جيدة؟ أنا قلق بعض الشيء لأنه يحتوي على بحثين حيث يجب القيام به حقا. هل هناك طريقة أفضل للتحقق من وجود وتعيين القيمة؟

هل كانت مفيدة؟

المحلول

عن طريق التحقق مع exists, ، يمكنك منع التدوير. يرى Autovivification: ما هو ولماذا يهمني؟.

تحديث: مثل الشقوق يشير أدناه، لا يأتي Autovivification في العبور في المثال الذي نشرته. أفترض أن القانون الفعلي ينطوي على تجزئة متعددة المستويات.

هنا هو التوضيح:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my (%hash, $x);

if ( exists $hash{test}->{vivify} ) {
    $x = $hash{test}->{vivify}->{now};
}

print Dumper \%hash;

$x = $hash{test}->{vivify}->{now};

print Dumper \%hash;

__END__


C:\Temp> t
$VAR1 = {
    'test' => {}
};
$VAR1 = {
    'test' => {
        'vivify' => {}
    }
};

نصائح أخرى

يمكنك استخدام تطبيق هاش :: eltilLock_keys إلى التجزئة. ثم قم بتنفيذ مهامك داخل Eval.

#!/usr/bin/perl
use Hash::Util qw/lock_keys/;

my %a = (
    1 => 'one',
    2 => 'two'
);

lock_keys(%a);

eval {$val = $a{2}};     # this assignment completes
eval {$val = $a{3}};     # this assignment aborts
print "val=$val\n";      # has value 'two'

يمكنك أن تفعل ذلك مع بحث واحد مثل هذا:

$tmp = $ids{$name};
$id = $tmp if (defined $tmp);

ومع ذلك، لن أزعجني إلا إذا رأيت أن ذلك كان عنق الزجاجة

إذا لم تكن تجزئة متعددة المستويات، فيمكنك القيام بذلك:

$id = $ids{$name} || 'foo';

أو إذا كان معرف $ لديه بالفعل قيمة:

$id ||= $ids{$name};

حيث "Foo" هي قيمة افتراضية أو من خلال. إذا كانت علامة تجزئة متعددة المستويات، فستحصل على "موجود" لتجنب التنبئة التي تمت مناقشتها مسبقا في مؤشر الترابط أو عدم استخدامه إذا لم يكن التدويل مشكلة.

إذا كنت أريد أداء عالي، فأنا اعتدت على كتابة هذا المصطلح عندما تريد إنشاء التجزئة كما هي المجموعة:

my %h;
for my $key (@some_vals) {
  ...
  $h{$key} = undef unless exists $h{$key};
  ...
}

return keys %h;

هذا الرمز أسرع قليلا من استخدامه $h{$key}++. exists يتجنب المهمة عديمة الفائدة و undef يتجنب التخصيص للقيمة. أفضل إجابة بالنسبة لك هي: معيار ذلك! أعتقد ذلك exists $ids{$name} أسرع قليلا من $id=$ids{$name} وإذا كان لديك نسبة ملكة جمال كبيرة، يمكن أن يكون الإصدار الخاص بك مع وجود أسرع من التعيين والاختبار بعد.

على سبيل المثال، إذا أردت أن تقاطع المجموعات السريعة، فسوف كتبت شيئا كهذا.

sub intersect {
  my $h;
  @$h{@{shift()}} = ();
  my $i;
  for (@_) {
    return unless %$h;
    $i = {};
    @$i{grep exists $h->{$_}, @$_} = ();
    $h = $i;
  }
  return keys %$h;
}

الأداء غير مهم في هذه الحالة، انظر "DEVEL :: NYTPROF". ولكن للإجابة على سؤالك:

إذا كانت القيمة في التجزئة لا توجد، "موجود" سريع جدا

if(exists $ids{$name}){
    $id = $ids{$name};
}

ولكن إذا كان موجودا يتم إجراء بحث ثان. إذا كانت القيمة من المرجح أن توجد من صنع نظرة واحدة فقط ستكون أسرع

$id = $ids{$name};
if($id){
    #....
}

شاهد هذا المعيار Littel من قائمة بريدية بيرل.

#!/usr/bin/perl -w
use strict;
use Benchmark qw( timethese );

use vars qw( %hash );
@hash{ 'A' .. 'Z', 'a' .. 'z' } = (1) x 52;

my $key = 'xx';
timethese 10000000, {
        'defined' => sub {
                if (defined $hash{$key}) { my $x = $hash{$key}; return $x; };
                return 0;
        },
        'defined_smart' => sub {
                my $x = $hash{$key};
                if (defined $x) {
                        return $x;
                };
                return 0;
        },
        'exists' => sub {
                if (exists $hash{$key}) { my $x = $hash{$key}; return $x; };
                return 0;
        },
        'as is' => sub {
                if ($hash{$key}) { my $x = $hash{$key}; return $x; };
                return 0;
        },
        'as is_smart' => sub {
                my $x = $hash{$key};
                if ($x) { return $x; };
                return 0;
        },

};

باستخدام مفتاح ('XX') الذي لا يوجد يظهر أن "موجود" هو الفائز.

Benchmark: timing 10000000 iterations of as is, as is_smart, defined, defined_smart, exists...
     as is:  1 wallclock secs ( 1.52 usr +  0.00 sys =  1.52 CPU) @ 6578947.37/s (n=10000000)
as is_smart:  3 wallclock secs ( 2.67 usr +  0.00 sys =  2.67 CPU) @ 3745318.35/s (n=10000000)
   defined:  3 wallclock secs ( 1.53 usr +  0.00 sys =  1.53 CPU) @ 6535947.71/s (n=10000000)
defined_smart:  3 wallclock secs ( 2.17 usr +  0.00 sys =  2.17 CPU) @ 4608294.93/s (n=10000000)
    exists:  1 wallclock secs ( 1.33 usr +  0.00 sys =  1.33 CPU) @ 7518796.99/s (n=10000000)

باستخدام مفتاح ('x') الذي يظهر أن "كما is_smart 'هو الفائز.

Benchmark: timing 10000000 iterations of as is, as is_smart, defined, defined_smart, exists...
     as is:  3 wallclock secs ( 2.76 usr +  0.00 sys =  2.76 CPU) @ 3623188.41/s (n=10000000)
as is_smart:  3 wallclock secs ( 1.81 usr +  0.00 sys =  1.81 CPU) @ 5524861.88/s (n=10000000)
   defined:  3 wallclock secs ( 3.42 usr +  0.00 sys =  3.42 CPU) @ 2923976.61/s (n=10000000)
defined_smart:  2 wallclock secs ( 2.32 usr +  0.00 sys =  2.32 CPU) @ 4310344.83/s (n=10000000)
    exists:  3 wallclock secs ( 2.83 usr +  0.00 sys =  2.83 CPU) @ 3533568.90/s (n=10000000)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top