web-dev-qa-db-fra.com

Comment puis-je énumérer une table de hachage en tant que paires clé-valeur / filtrer une table de hachage par une collection de valeurs de clé

Note de l'éditeur: Cette question a une histoire compliquée, mais se résume à ceci:
* Pour apprendre à énumérer les entrées d'une table de hachage par ses paires clé-valeur, voir la réponse acceptée .
* Pour apprendre à filtrer une hashtable par a collection de valeurs de clé, voir l'autre réponse .


Je pense que je suis à nouveau tombé dans le problème X Y, ma question initiale concernait le filtrage d'une table de hachage. J'ai découvert qu'il était plus facile de filtrer avant de créer la table de hachage. Question répondu, non?

Non, le problème de Y faisait boucler chaque clé et utilisait les valeurs que @briantist m'a aidées.

Mon objectif est de passer en boucle sur les noms de clé, qui sont des horodatages, et de planifier une tâche en utilisant le nom de clé en tant que nom de tâche et déclencheur.

Je crée une table de hachage à partir d'un fichier CSV en utilisant Group-Object -AsHashTable -AsString - edit, il est utile de mentionner ici que filtrer le fichier CSV avant de créer HashTable ne fait que simplifier les choses en utilisant le Pipeline ou le script .

Par 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 revue les noms de clé et de pouvoir afficher les noms de clé 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 sais tout simplement pas comment obtenir les valeurs des clés qui m'intéressent.

J'ai trouvé les travaux suivants, mais uniquement lorsque j'entre un nom de clé manuellement. Je ne suis pas sûr de savoir comment combiner les deux boucles.

($val.GetEnumerator() | Where {$_.key -eq '06-11-16 18:00'} | ForEach-Object { $_.value }).Server
22
user4317867

Vous avez quelques options ici.

Enumérant à travers les clés:

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

Énumération des paires clé-valeur (que vous avez découvertes, mais que vous n'utilisez peut-être pas efficacement):

foreach ($kvp in $var.GetEnumerator()) {
    $key = $kvp.Key
    $val = $kvp.Value
}
38
briantist

Pour compléter réponse utile de briantist en ciblant le filtrage d'une table de hachage par un tableau de valeurs de clé (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[]

Pour approfondir les paires clé-valeur correspondantes , dirigez-le simplement vers % (ForEach-Object) Et accédez à $_.Key Et $_.Value (Valeur):

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

La commande équivalente utilisant une méthode plus efficace foreach loop à la place du pipeline:

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

Remarque: Dans PSv2 :
L'opérateur * -in n'est pas pris en charge, mais vous pouvez utiliser -contains à la place avec les opérandes swapped:
'one', 'two' -contains $key
* dans le pipeline, utilisez Where-Object { 'one', 'two' -contains $_.Key }

Avec l'exemple de hashtable, cela donne:

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

Notez la différence entre l'ordre des clés dans la sortie et celui de la définition. dans PSv3 +, vous pouvez créer ordonné des hashtables ([ordered] @{ ... }) pour préserver l'ordre de la définition.

La technique de filtrage de clé utilisée ci-dessus est pas limitée au filtrage par littéral tableaux de clés; toute collection (chaîne) fera comme le RHS de l'opérande -in, tel que la collection .Keys d'un différent hashtable:

# 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 tableau static filter-keys.

Enfin, si vous voulez filtrer une table de hachage à la place ou créer un nouveau hashtable avec uniquement les entrées filtré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) }
} 

En aparté:

Le format de sortie par défaut pour [System.Collections.DictionaryEntry] (Et donc les hashtables ([System.Collections.Hashtable]) Utilise le nom de colonne Name plutôt que Key; Name est défini comme un propriété d'alias de Key ajouté par PowerShell (il ne fait pas partie du [System.Collections.DictionaryEntry]. NET. définition de type ; vérifier avec
@{ one = 1 }.GetEnumerator() | Get-Member).

9
mklement0