2009-06-10 17 views
5

veces puedo acceder a un hash de esta manera:¿Búsqueda de hash adicional usando 'exists'?

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

¿Eso es una buena práctica? Estoy un poco preocupado de que contenga dos búsquedas donde realmente se debe hacer uno. ¿Hay una mejor manera de verificar la existencia y asignar el valor?

Respuesta

10

Al marcar con exists, se impide que autovivification. Ver Autovivification : What is it and why do I care?.

ACTUALIZACIÓN: Como trendels señala a continuación, autovigilancia no entra en juego en el ejemplo que ha publicado. Estoy asumiendo que el código real involucra hashes multinivel.

Aquí es una ilustración:

#!/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' => {} 
    } 
}; 
+1

¿'Existe' es más barato que recuperar el valor? Después de todo, no tiene que seguir una lista vinculada cuando encuentra una colisión. – Frank

+1

En este caso particular, sin embargo, la clave hash para "$ name" * no * se crearía por autovigilancia. Solo intentar acceder a una clave anidada a un nivel más profundo, como "$ id = $ ids {$ name} {other}" crearía la clave "$ name". – trendels

+0

@trendels Correcto, pero supuse que el OP se había simplificado demasiado. Aún así, debería haberlo señalado. –

1

Puede hacerlo con una consulta de la siguiente manera:

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

Sin embargo, no me molestaría menos vi que era un cuello de botella

+0

Bien, pero eso no es exactamente lo mismo. 'exists' comprueba si hay un valor (puede ser undef), mientras que define checks si hay un valor y no es undef. – Frank

+0

Tiene un punto, pero al final del día si no existe o si existe pero no está definido, obtendrá undef. ¿Estás viendo un rendimiento aquí que te preocupa tanto o es puramente académico? Lo pregunto solo por curiosidad, nada más ... –

+1

¡Puramente académico! Simplemente no me gustó el hecho de que estoy revisando el hash dos veces. Lo cambiaré y simplemente haré una verificación 'definida', como sugirió. – Frank

0

si no es un hash de varios niveles se puede hacer esto:

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

o si $ id ya tiene un valor:

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

donde 'foo' es un valor predeterminado o fallido. Si se trata de un hash de varios niveles, debe usar 'exists' para evitar la autovibición que se discutió anteriormente en el hilo o no usarlo si la autovibición no va a ser un problema.

+0

p.s. no hay "hilos" Las preguntas tienen respuestas, respuestas y preguntas tienen comentarios. Sin hilos. –

+0

también ps. no hay pestañas "anteriores", ver "antiguas", "nuevas" y "votos" que mezclan el orden. –

+0

¿Qué sucede cuando $ ids {$ name} es 0 o está vacío o undef? – innaM

1

Puede aplicar Hash::Util's lock_keys al hash. Luego realice sus tareas dentro de una evaluación.

#!/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' 
0

Si quiero alto rendimiento que estoy acostumbrado a escribir este idioma cuando desee crear almohadilla, como conjunto:

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

return keys %h; 

Este código es poco más rápido de lo que comúnmente utilizado $h{$key}++. exists evita la asignación inútil y undef evita la asignación de valor. La mejor respuesta para usted es: ¡comparta esto! Supongo que exists $ids{$name} es un poco más rápido que $id=$ids{$name} y si tiene una gran relación de fallas, su versión con existe puede ser más rápida que la asignación y la prueba posterior.

Por ejemplo, si quiero una intersección de conjuntos rápidos, escribiría algo como esto.

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

La creación de claves que aún no están en el hash generalmente no es una buena idea. No desea comenzar a almacenar claves que no desea. –

+0

Usted se equivoca. Pruébalo otra vez. –

+0

Esa palabra no significa lo que piensas que significa. – Ether

0

El rendimiento no es importante en este caso, consulte "Devel :: NYTProf". Pero para responder a su pregunta:

si no existe el valor en el hash, "existe" es muy rápido

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

pero si lo hace existe una segunda búsqueda se realiza. si el valor es probable que exista en vez de hacer sólo una mirada hacia arriba será más rápido

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

ver este punto de referencia Littel de una lista de correo de Perl.

#!/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; 
     }, 

}; 

usando una clave ('xx') que no existe muestra que 'existe' es el ganador.

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) 

utilizando una clave ('x') que hace existe muestra que 'como is_smart' es el ganador.

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) 
Cuestiones relacionadas