En Perl, los hashes (arreglos asociativos) son una herramienta poderosa para almacenar pares clave-valor. Sin embargo, trabajar con ellos requiere atención, especialmente al iterar y modificar la estructura al mismo tiempo. Los detalles pasados por alto aquí pueden llevar a errores que son difíciles de diagnosticar.
Los arreglos asociativos fueron introducidos en las primeras versiones de Perl (Perl 1/2), lo que los convirtió en uno de los primeros lenguajes con soporte completo para hashes a nivel de núcleo. Con el tiempo, se añadieron funcionalidades adicionales: iteración a través de each, eliminación (delete), transformación masiva (map, grep) y lidiar con cambios de tamaño/contenido durante la iteración.
Iterar sobre un hash y modificar su contenido al mismo tiempo, especialmente eliminando elementos, puede llevar a efectos inesperados: omisiones de elementos, pasar por las mismas claves de nuevo, o incluso un ciclo infinito. Además, el orden de iteración de las claves no está garantizado y puede cambiar entre versiones de Perl.
each, ya que el cursor interno se descuadra.keys, luego itera sobre ella en un ciclo separado y elimina.while (my ($k, $v) = each %h) para una iteración normal, pero no la combines con delete dentro del ciclo si no quieres sorpresas.Ejemplo de eliminación correcta de elementos:
my %h = (a=>1, b=>2, c=>3); for my $k (keys %h) { delete $h{$k} if $h{$k} == 2; }
Ejemplo de enfoque incorrecto:
while (my ($k, $v) = each %h) { delete $h{$k}; # Esto puede llevar a omisiones de claves }
Características clave:
¿Se pueden eliminar elementos de un hash de manera segura dentro de un ciclo while (each %h)?
No, esto puede llevar a omisiones en partes del hash debido al reset del cursor de iteración interno.
¿Qué sucede con el orden de las claves después de eliminar elementos de un hash?
No hay garantía sobre el orden y este puede cambiar. Además, el orden de iteración entre programas en la misma versión de Perl puede ser diferente.
¿Se puede modificar el valor de un elemento del hash dentro de la iteración a través de each?
Sí, modificar el valor (pero no la estructura) es seguro.
Ejemplo:
while (my ($k, $v) = each %h) { $h{$k} = $v + 10; }
Uso de eliminación de elementos a través de each en un solo ciclo:
my %h = (a=>1, b=>2, c=>3); while (my ($k, $v) = each %h) { delete $h{$k} if $v == 1; }
Ventajas:
Desventajas:
Creación de una lista de claves para eliminar:
my %h = (a=>1, b=>2, c=>3); for my $k (keys %h) { delete $h{$k} if $h{$k} == 1; }
Ventajas:
Desventajas: