¿Cómo puedo combinar hashes en Perl?


¿Cuál es la mejor manera de combinar ambos hashes en %hash1? Siempre sé que %hash2 y % hash1 siempre tienen claves únicas. También preferiría una sola línea de código si es posible.

$hash1{'1'} = 'red';
$hash1{'2'} = 'blue';
$hash2{'3'} = 'green';
$hash2{'4'} = 'yellow';
Author: dreftymac, 2008-12-08

4 answers

Respuesta rápida (TL; DR)


    %hash1 = (%hash1, %hash2)

    ## or else ...

    @hash1{keys %hash2} = values %hash2;

    ## or with references ...

    $hash_ref1 = { %$hash_ref1, %$hash_ref2 };

Descripción general

  • Contexto: Perl 5.x
  • Problema: El usuario desea combinar dos hashes1 en una sola variable

Solución

  • utilice la sintaxis anterior para variables simples
  • use Hash:: Merge para variables anidadas complejas

Trampas

  • Qué hacer cuando ambos hashes contienen una o más claves duplicadas
    • Si un par clave-valor con un valor vacío nunca sobrescribir un par clave-valor con un valor no vacío?
    • ¿Qué constituye un valor vacío vs no vacío en primer lugar? (eg. undef, cadena vacía, false, falsy ...)
    • (Nota: la pregunta original descarta este escenario, pero es importante considerarlo)

Véase también


Notas al pie

1 * (aka matriz asociativa , aka diccionario )

 150
Author: dreftymac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-13 09:21:52

Echa un vistazo perlfaq4: Cómo combinar dos hashes. Ya hay mucha información buena en la documentación de Perl y puede tenerla de inmediato en lugar de esperar a que alguien más la responda. :)


Antes de decidir fusionar dos hashes, debe decidir qué hacer si ambos hashes contienen claves que son las mismas y si desea dejar los hashes originales como estaban.

Si desea conservar los hashes originales, copie un hash (%hash1) a un nuevo hash (%new_hash), luego agregue las claves del otro hash (%hash2 al nuevo hash. Comprobar que la clave ya existe en %new_hash te da la oportunidad de decidir qué hacer con los duplicados:

my %new_hash = %hash1; # make a copy; leave %hash1 alone

foreach my $key2 ( keys %hash2 )
    {
    if( exists $new_hash{$key2} )
        {
        warn "Key [$key2] is in both hashes!";
        # handle the duplicate (perhaps only warning)
        ...
        next;
        }
    else
        {
        $new_hash{$key2} = $hash2{$key2};
        }
    }

Si no desea crear un nuevo hash, todavía puede usar esta técnica de bucle; simplemente cambie %new_hash a %hash1.

foreach my $key2 ( keys %hash2 )
    {
    if( exists $hash1{$key2} )
        {
        warn "Key [$key2] is in both hashes!";
        # handle the duplicate (perhaps only warning)
        ...
        next;
        }
    else
        {
        $hash1{$key2} = $hash2{$key2};
        }
    }

Si no le importa que un hash sobrescriba las claves y los valores del otro, podría usar un hash slice para agregar un hash a otro. En este caso, los valores de % hash2 reemplazan los valores de %hash1 cuando tienen claves en común:

@hash1{ keys %hash2 } = values %hash2;
 37
Author: brian d foy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-18 10:48:08

Esta es una vieja pregunta, pero sale muy alto en mi búsqueda de Google para 'perl merge hashes' - y sin embargo no menciona el muy útil módulo CPAN Hash:: Merge

 13
Author: LeeGee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-03 13:13:16

Para referencias hash. Debes usar llaves como las siguientes:

$hash_ref1 = {%$hash_ref1, %$hash_ref2};

Y no la respuesta sugerida arriba usando paréntesis:

$hash_ref1 = ($hash_ref1, $hash_ref2);
 4
Author: JeanieJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-07 18:40:27