La regla general es utilizar la función que mejor se adapte a sus necesidades.
Si solo quiere las claves y no planea leer ninguno de los valores, use keys ():
foreach my $key (keys %hash) { ... }
Si solo desea los valores, use values ():
foreach my $val (values %hash) { ... }
Si necesita las claves y los valores, use cada ():
keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }
Si planea cambiar las claves del hash de alguna manera, excepto para eliminar la clave actual durante la iteración, entonces no debe usar cada (). Por ejemplo, este código para crear un nuevo conjunto de teclas en mayúsculas con valores duplicados funciona bien usando keys ():
%h = (a => 1, b => 2);
foreach my $k (keys %h)
{
$h{uc $k} = $h{$k} * 2;
}
produciendo el hash resultante esperado:
(a => 1, A => 2, b => 2, B => 4)
Pero usando cada () para hacer lo mismo:
%h = (a => 1, b => 2);
keys %h;
while(my($k, $v) = each %h)
{
$h{uc $k} = $h{$k} * 2; # BAD IDEA!
}
produce resultados incorrectos de formas difíciles de predecir. Por ejemplo:
(a => 1, A => 2, b => 2, B => 8)
Sin embargo, esto es seguro:
keys %h;
while(my($k, $v) = each %h)
{
if(...)
{
delete $h{$k}; # This is safe
}
}
Todo esto se describe en la documentación de perl:
% perldoc -f keys
% perldoc -f each
Una cosa que debe tener en cuenta al usar
each
es que tiene el efecto secundario de agregar "estado" a su hash (el hash tiene que recordar cuál es la clave "siguiente"). Cuando se usa código como los fragmentos publicados anteriormente, que recorren todo el hash de una sola vez, esto no suele ser un problema. Sin embargo, se encontrará con problemas difíciles de rastrear (hablo por experiencia;), cuando useeach
junto con declaraciones comolast
oreturn
para salir delwhile ... each
ciclo antes de haber procesado todas las claves.En este caso, el hash recordará qué claves ya ha devuelto, y cuando lo use
each
la próxima vez (tal vez en un fragmento de código totalmente no relacionado), continuará en esta posición.Ejemplo:
Esto imprime:
¿Qué pasó con las teclas "bar" y baz "? Todavía están allí, pero la segunda
each
comienza donde se quedó la primera y se detiene cuando llega al final del hash, por lo que nunca las vemos en el segundo ciclo.fuente
El lugar donde
each
puede causarle problemas es que es un iterador verdadero, sin alcance. A modo de ejemplo:Si necesita asegurarse de que
each
obtenga todas las claves y valores, debe asegurarse de usarkeys
ovalues
primero (ya que eso restablece el iterador). Consulte la documentación de cada uno .fuente
El uso de cada sintaxis evitará que se genere todo el conjunto de claves a la vez. Esto puede ser importante si está utilizando un hash vinculado a una base de datos con millones de filas. No desea generar la lista completa de claves de una sola vez y agotar su memoria física. En este caso, cada uno sirve como iterador, mientras que las claves realmente generan la matriz completa antes de que comience el ciclo.
Por tanto, el único lugar en el que "cada uno" es de uso real es cuando el hash es muy grande (en comparación con la memoria disponible). Es probable que eso solo suceda cuando el hash en sí no vive en la memoria, a menos que esté programando un dispositivo de recolección de datos portátil o algo con poca memoria.
Si la memoria no es un problema, normalmente el paradigma del mapa o de las claves es el paradigma más preventivo y más fácil de leer.
fuente
Algunas reflexiones diversas sobre este tema:
values
devuelve alias, lo que significa que modificarlos modificará el contenido del hash. Esto es por diseño, pero puede que no sea lo que desea en algunas circunstancias.each
. Esto no es ciertokeys
ya queeach
es un iterador mientraskeys
devuelve una lista.fuente
También utilizo siempre el método 2. El único beneficio de usar cada uno es que si solo está leyendo (en lugar de reasignar) el valor de la entrada de hash, no está desreferenciando constantemente el hash.
fuente
Puede que me muerda, pero creo que es una preferencia personal. No puedo encontrar ninguna referencia en los documentos a que cada () sea diferente de las claves () o los valores () (aparte de la respuesta obvia de "devuelven cosas diferentes". De hecho, los documentos indican que usan el mismo iterador y todos devuelve valores de lista reales en lugar de copias de ellos, y que modificar el hash mientras se itera sobre él usando cualquier llamada es malo.
Dicho todo esto, casi siempre uso keys () porque para mí es más autodocumentado acceder al valor de la clave a través del propio hash. De vez en cuando utilizo values () cuando el valor es una referencia a una estructura grande y la clave del hash ya estaba almacenada en la estructura, momento en el que la clave es redundante y no la necesito. Creo que he usado cada () 2 veces en 10 años de programación Perl y probablemente fue la elección incorrecta en ambas ocasiones =)
fuente
Usualmente uso
keys
y no puedo pensar en la última vez que usé o leí un uso deeach
.¡No te olvides de
map
, dependiendo de lo que estés haciendo en el bucle!fuente
Yo diría:
Esto le da 2 ventajas principales:
No creo que sea más costoso usar claves sobre cada una, por lo que no es necesario dos construcciones diferentes para lo mismo en su código.
fuente
keys
uso de memoria aumenta enhash-size * avg-key-size
. Dado que el tamaño de la clave solo está limitado por la memoria (ya que son solo elementos de matriz como "sus" valores correspondientes bajo el capó), en algunas situaciones puede ser prohibitivamente más costoso tanto en el uso de memoria como en el tiempo necesario para hacer la copia.