Comment puis-je énumérer un hashtable comme paire de valeurs / filtrer un hashtable par une collection de valeurs clés

note de l'Éditeur: Cette question a une histoire compliquée, mais se résume à ceci:

* Apprendre à énumérer les entrées d'un hashtable par son les paires clé-valeur la réponse acceptée.

* Apprendre à filtre un hashtable par un collection des valeurs clésles autres répondre à.


je pense que je suis tombé dans le problème X Y encore une fois, ma question initiale était au sujet du filtrage d'une table de hachage. J'ai découvert qu'il est plus facile de filtrer avant de créer la table de hachage. Réponse à la Question, non?

non, le problème était de boucler chaque touche et d'utiliser les valeurs avec lesquelles @briantist m'a aidé.

mon but est de passer en boucle les noms des clés, qui sont des horodateurs, et de programmer une tâche en utilisant le nom de la clé comme tâche le nom et la détente.

je crée une table de hachage à partir D'un fichier CSV en utilisant Group-Object -AsHashTable -AsString-edit, il est intéressant de mentionner ici que filtrer le CSV avant de créer le HashTable ne fait que rendre les choses plus faciles dans le Pipeline ou script.

comme exemple:

Import-CSV (ls -path D: -Filter source*.csv | sort LastWriteTime | Select -Last 1).FullName |
 where {$_.TimeCorrected -ne 'ManualRebootServer'} |
 group TimeCorrected -AsHashTable -AsString

j'essaie de passer en boucle les noms des clés et d'afficher les noms des clés en utilisant:

$var = Import-Csv csv123.csv | Group-Object Value1 -AsHashTable -AsString

foreach ($key in $var.Keys){"The key name is $key"}

#Create a scheduled task named and triggered based on the HashTable keyname
#test test test
foreach ($key in $var.keys){IF($key -ne 'ManualRebootServer'){"Register-ScheduledJob"}}

Je ne suis pas sûr comment obtenir les valeurs des clés que je suis intéressé dans.

j'ai trouvé les travaux suivants, mais seulement quand j'entre un nom de clé manuellement. Je ne sais pas comment combiner les deux boucles.

($val.GetEnumerator() | Where {$_.key -eq '06-11-16 18:00'} | ForEach-Object { $_.value }).Server
19
demandé sur Community 2016-06-05 01:55:25

2 réponses

Vous avez quelques options ici.

l'Énumération par le biais de touches:

foreach ($key in $var.Keys) {
    $value = $var[$key]
    # or
    $value = $var.$key 
}

l'Énumération des paires clé-valeur (ce que vous avez découvert, mais ne peut pas utiliser efficacement):

foreach ($kvp in $var.GetEnumerator()) {
    $key = $kvp.Key
    $val = $kvp.Value
}
27
répondu briantist 2017-09-14 15:08:55

pour compléter briantist de réponse utile en se concentrant sur filtrage d'un hashtable par un tableau de valeurs clés (syntaxe PSv3+):

# Sample hashtable.
$ht = @{ one = 1; two = 2; three = 3 }

# Filter it by an array of key values; applying .GetEnumerator() yields an array
# of [System.Collections.DictionaryEntry] instances, which have
# a .Key property and a .Value property.
$ht.GetEnumerator()  | ? Key -in 'one', 'two'

# Similarly, the *output* - even though it *looks* like a hashtable - 
# is a regular PS *array* ([Object[]]) containing [System.Collections.DictionaryEntry]
# entries (2 in this case).
$arrFilteredEntries = $ht.GetEnumerator()  | ? Key -in 'one', 'two'
$arrFilteredEntries.GetType().Name # -> Object[]

autres processus de l'appariement des paires clé-valeur, il suffit de tuyau % (ForEach-Object) et l'accès $_.Key et $_.Value (valeur):

$ht.GetEnumerator()  | ? Key -in 'one', 'two' | 
  % { "Value for key '$($_.Key)': $($_.Value)" }

la commande équivalente utiliser un foreachboucle à la place de la pipeline:

foreach ($key in $ht.Keys) { 
  if ($key -in 'one', 'two') { "Value for key '$($key)': $($ht.$key)" }
}

Note: In PSv2:

* l'opérateur -in n'est pas supporté, mais vous pouvez utiliser -contains à la place avec les opérandes échangé:

'one', 'two' -contains $key

* dans le pipeline, utilisez Where-Object { 'one', 'two' -contains $_.Key }

avec le hashtable échantillon, cela donne:

Value for key 'two': 2
Value for key 'one': 1

notez comment l'ordre de touche dans la sortie diffère de l'ordre de définition; dans PSv3+, vous pouvez créer commandés tables de hachage ([ordered] @{ ... }) pour préserver l'ordre des définitions.

la technique de filtrage des clés utilisée ci-dessus est limité au filtrage par littérale tableaux de clés; n'importe quelle collection (string) fera comme le RHS du -in opérande, comme le .Keys collection table de hachage:

# Sample input hashtable.
$htInput = @{ one = 1; two = 2; three = 3 }

# Hashtable by whose keys the input hashtable should be filtered.
# Note that the entries' *values* are irrelevant here.
$htFilterKeys = @{ one = $null; two = $null }

# Perform filtering.
$htInput.GetEnumerator()  | ? Key -in $htFilterKeys.Keys | 
  % { "Value for key '$($_.Key)': $($_.Value)" }

# `foreach` loop equivalent:
foreach ($key in $htInput.Keys) {
  if ($key -in $htFilterKeys.Keys) { "Value for key '$($key)': $($htInput.$key)" }
}

Le résultat est le même que dans l'exemple avec le filtre statique-clés tableau.

Enfin, si vous voulez filtrer un hashtable au lieu de ou créer un table de hachage avec seulement filtré les entrées:

# *In-place* Updating of the hashtable.
# Remove entries other than the ones matching the specified keys.
# Note: The @(...) around $ht.Keys is needed to clone the keys collection before
# enumeration, so that you don't get an error about modifying a collection
# while it is being enumerated.
foreach ($key in @($ht.Keys)) { 
  if ($key -notin 'one', 'two') { $ht.Remove($key) } 
} 

# Create a *new* hashtable with only the filtered entries.
# By accessing the original's .Keys collection, the need for @(...) is obviated.
$htNew = $ht.Clone()
foreach ($key in $ht.Keys) { 
  if ($key -notin 'one', 'two') { $htNew.Remove($key) }
} 

à part:

le format de sortie par défaut pour [System.Collections.DictionaryEntry] (et donc les tables de hashage ([System.Collections.Hashtable]) utilise le nom de la colonne Name plutôt que Key;Name est défini comme un propriété d'aliasKey ajouté par PowerShell (ne fait pas partie du [System.Collections.DictionaryEntry]définition de type .NET; vérifier avec

@{ one = 1 }.GetEnumerator() | Get-Member).

8
répondu mklement0 2018-07-26 15:14:49