Saltar al contenido

Fusión de tablas hash en PowerShell: ¿cómo?

Sé libre de divulgar nuestro espacio y códigos con tus amigos, necesitamos tu ayuda para aumentar esta comunidad.

Solución:

Merge-Hashtables

en lugar de eliminar keys podría considerar simplemente sobrescribirlos:

$h1 = @a = 9; b = 8; c = 7
$h2 = @b = 6; c = 5; d = 4
$h3 = @c = 3; d = 2; e = 1


Function Merge-Hashtables 
    $Output = @
    ForEach ($Hashtable in ($Input + $Args)) 
        If ($Hashtable -is [Hashtable]) 
            ForEach ($Key in $Hashtable.Keys) $Output.$Key = $Hashtable.$Key
        
    
    $Output

Para este cmdlet, puede usar varias sintaxis y no está limitado a dos tablas de entrada: Uso de la canalización: $h1, $h2, $h3 | Merge-Hashtables

Usando argumentos: Merge-Hashtables $h1 $h2 $h3

O una combinación: $h1 | Merge-Hashtables $h2 $h3

Todos los ejemplos anteriores devuelven la misma tabla hash:

Name                           Value
----                           -----
e                              1
d                              2
b                              6
c                              3
a                              9

Si hay algún duplicado keys en las tablas hash proporcionadas se toma el valor de la última tabla hash.


(Agregado 2017-07-09)

Merge-Hashtables versión 2

En general, prefiero funciones más globales que se pueden personalizar con parámetros para necesidades específicas como en la pregunta original: “sobrescribir key-valor pares en el primero si es el mismo key existe en el segundo”. ¿Por qué dejar que el último anule y no el primero? ¿Por qué eliminar nada en absoluto? Tal vez alguien más quiera fusionar o unir los valores u obtener el valor más grande o solo el promedio…
La versión a continuación ya no admite el suministro de tablas hash como argumentos (solo puede canalizar tablas hash a la función), pero tiene un parámetro que le permite decidir cómo tratar el valor array en entradas duplicadas operando el valor array asignado al hash key presentado en el objeto actual ($_).

Función

Function Merge-Hashtables([ScriptBlock]$Operator) 
    $Output = @
    ForEach ($Hashtable in $Input) 
        If ($Hashtable -is [Hashtable]) 
            ForEach ($Key in $Hashtable.Keys) $Output.$Key = If ($Output.ContainsKey($Key)) @($Output.$Key) + $Hashtable.$Key Else  $Hashtable.$Key
        
    
    If ($Operator) ForEach ($Key in @($Output.Keys)) $_ = @($Output.$Key); $Output.$Key = Invoke-Command $Operator
    $Output

Sintaxis

HashTable[]  | Merge-Hashtables [-Operator ]

Por defecto
De forma predeterminada, todos los valores de las entradas de la tabla hash duplicadas se agregarán a un array:

PS C:> $h1, $h2, $h3 | Merge-Hashtables

Name                           Value
----                           -----
e                              1
d                              4, 2
b                              8, 6
c                              7, 5, 3
a                              9

Ejemplos
Para obtener el mismo resultado que la versión 1 (usando el últimos valores) utilice el comando: $h1, $h2, $h3 | Merge-Hashtables $_[-1]. Si desea utilizar el primeros valores en cambio, el comando es: $h1, $h2, $h3 | Merge-Hashtables $_[0] o la valores más grandes: $h1, $h2, $h3 | Merge-Hashtables ($_ .

Más ejemplos:

PS C:> $h1, $h2, $h3 | Merge-Hashtables  Measure-Object -Average).Average # Take the average values"

Name                           Value
----                           -----
e                              1
d                              3
b                              7
c                              5
a                              9


PS C:> $h1, $h2, $h3 | Merge-Hashtables $_ -Join "" # Join the values together

Name                           Value
----                           -----
e                              1
d                              42
b                              86
c                              753
a                              9


PS C:> $h1, $h2, $h3 | Merge-Hashtables $_  # Sort the values list

Name                           Value
----                           -----
e                              1
d                              2, 4
b                              6, 8
c                              3, 5, 7
a                              9

Veo dos problemas:

  1. La riostra abierta debe estar en la misma línea que Foreach-object
  2. No debe modificar una colección mientras enumera a través de una colección

El siguiente ejemplo ilustra cómo solucionar ambos problemas:

function mergehashtables($htold, $htnew)
 foreach-object 
        $key = $_
        if ($htnew.containskey($key))
        
            $htold.remove($key)
        
    
    $htnew = $htold + $htnew
    return $htnew

No es una respuesta nueva, esto es funcionalmente igual que @Josh-Petitt con mejoras.

En esta respuesta:

  • Merge-HashTable usa la sintaxis correcta de PowerShell si desea colocar esto en un módulo
  • No era idempotente. Agregué la clonación de la entrada HashTable, de lo contrario, su entrada fue golpeada, no fue una intención
  • agregó un ejemplo apropiado de uso
function Merge-HashTable 
    param(
        [hashtable] $default, # Your original set
        [hashtable] $uppend # The set you want to update/append to the original set
    )

    # Clone for idempotence
    $default1 = $default.Clone();

    # We need to remove any key-value pairs in $default1 that we will
    # be replacing with key-value pairs from $uppend
    foreach ($key in $uppend.Keys) 
        if ($default1.ContainsKey($key)) 
            $default1.Remove($key);
        
    

    # Union both sets
    return $default1 + $uppend;


# Real-life example of dealing with IIS AppPool parameters
$defaults = @
    enable32BitAppOnWin64 = $false;
    runtime = "v4.0";
    pipeline = 1;
    idleTimeout = "1.00:00:00";
 ;
$options1 = @ pipeline = 0; ;
$options2 = @ enable32BitAppOnWin64 = $true; pipeline = 0; ;

$results1 = Merge-HashTable -default $defaults -uppend $options1;
# Name                           Value
# ----                           -----
# enable32BitAppOnWin64          False
# runtime                        v4.0
# idleTimeout                    1.00:00:00
# pipeline                       0

$results2 = Merge-HashTable -default $defaults -uppend $options2;
# Name                           Value
# ----                           -----
# idleTimeout                    1.00:00:00
# runtime                        v4.0
# enable32BitAppOnWin64          True
# pipeline                       0

Aquí tienes las reseñas y calificaciones

Si te animas, puedes dejar una sección acerca de qué te ha parecido este escrito.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *