Orden de Claves de los Hashtables de Powershell


Usando Powershell 2.0 ¿Hay alguna manera de mantener el orden de las claves en una tabla hash a medida que se agregaron? Como un mecanismo push / pop.

Ejemplo:

$hashtable = @{}

$hashtable.Add("switzerland","berne")
$hashtable.Add("germany","berlin")
$hashtable.Add("spain","madrid")
$hashtable.Add("italy","rome")
$hashtable

Quiero mantener el orden en el que he añadido los elementos a la tabla hash.

Author: Loïc MICHEL, 2013-02-15

6 answers

No hay una solución integrada en powershell V1 / V2, querrá usar. net System.Collections.Specialized.OrderedDictionary

$order = New-Object System.Collections.Specialized.OrderedDictionary
$order.Add("switzerland","berne")
$order.Add("germany","berlin")


PS>$order

Name                           Value
----                           -----
switzerland                    berne
germany                        berlin

En PS V3 puedes lanzar a[ordenado]:

PS>[ordered]@{"switzerland"="berne";"germany"="berlin"}

Name                           Value
----                           -----
switzerland                    berne
germany                        berlin
 40
Author: Loïc MICHEL,
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
2013-02-15 09:02:44

Puedes usar un diccionario ordenado en su lugar: así:

$list = New-Object System.Collections.Specialized.OrderedDictionary
$list.Add("switzerland","berne")
$list.Add("germany","berlin")
$list.Add("spain","madrid")
$list.Add("italy","rome")
$list
 7
Author: Frode F.,
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
2013-02-15 09:01:11

Puede dar una clave secuencial a medida que agrega elementos:

$hashtable = @{}

$hashtable[$hashtable.count]=@("switzerland","berne")
$hashtable[$hashtable.count]=@("germany","berlin")
$hashtable[$hashtable.count]=@("spain","madrid")
$hashtable[$hashtable.count]=@("italy","rome")
$hashtable

Entonces, puede obtener elementos ordenados por la clave:

echo "`nHashtable keeping the order as they were added"
foreach($item in $hashtable.getEnumerator() | Sort Key)
{
    $item
}
 3
Author: Juan Antonio Tubío,
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-04-10 01:13:26

La forma PS1 de agregar miembro hashtable conserva el orden de agregar. No hay necesidad de utilizar el sistema.Colecciones.Especializar.Ordenaddiccionario.

$Hash = New-Object PSObject                                       
$Hash | Add-Member -MemberType NoteProperty -Name key1 -Value val1
$Hash | Add-Member -MemberType NoteProperty -Name key2 -Value val2
$Hash | Add-Member -MemberType NoteProperty -Name key3 -Value val3
 1
Author: Axel Limousin,
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
2013-09-01 11:33:29

Para la compatibilidad con versiones anteriores de PowerShell, puede considerar este cmdlet:

Function Order-Keys {
    param(
        [Parameter(Mandatory = $true,  ValueFromPipeline = $true)][HashTable]$HashTable,
        [Parameter(Mandatory = $false, Position = 1)][ScriptBlock]$Function,
        [Switch]$Descending
    )
    $Keys = $HashTable.Keys | ForEach {$_}                                      #Copy HashTable+KeyCollection
    For ($i = 0; $i -lt $Keys.Count - 1; $i++) {
        For ($j = $i + 1; $j -lt $Keys.Count; $j++) {
            $a = $Keys[$i]
            $b = $Keys[$j]
            If ($Function -is "ScriptBlock") {
                $a = $HashTable[$a] | ForEach $Function
                $b = $HashTable[$b] | ForEach $Function
            }
            If ($Descending) {$Swap = $a -lt $b} Else {$Swap = $a -gt $b}
            If ($Swap) {$Keys[$i], $Keys[$j] = $Keys[$j], $Keys[$i]}
        }
    }
    Return $Keys
}

Este cmdlet devuelve una lista de claves ordenadas por la definición de la función:

Ordenar por nombre:

$HashTable | Order-Keys | ForEach {Write-Host $_ $HashTable[$_]}
germany berlin
italy rome
spain madrid
switzerland berne

Ordenar por valor:

$HashTable | Order-Keys {$_} | ForEach {Write-Host $_ $HashTable[$_]}
germany berlin
switzerland berne
spain madrid
italy rome

También podrías considerar anidar tablas hash:

$HashTable = @{
    switzerland = @{Order = 1; Capital = "berne"}
    germany     = @{Order = 2; Capital = "berlin"}
    spain       = @{Order = 3; Capital = "madrid"}
    italy       = @{Order = 4; Capital = "rome"}
}

Por ejemplo, Ordenar por (hashed) ordenar propiedad y devolver la clave (país):

$HashTable | Order-Keys {$_.Order} | ForEach {$_}

O ordenar (descendente) por capital predefinido

$HashTable | Order-Keys {$_.Capital} -Descending | ForEach {$_}
 1
Author: iRon,
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-03-24 15:32:44
function global:sortDictionaryByKey([hashtable]$dictionary)
{
    return $dictionary.GetEnumerator() | sort -Property name;
}
 0
Author: user2174447,
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-08-30 22:42:04