web-dev-qa-db-ja.com

ハッシュテーブルをキーと値のペアとして列挙したり、キー値のコレクションでハッシュテーブルをフィルタリングするにはどうすればよいですか

編集者注:この質問には複雑な歴史がありますが、要約すると次のとおりです。
*enumerateキーと値のペアによるハッシュテーブルのエントリの方法については 受け入れられた答え
*フィルターキー値のコレクションによるハッシュテーブルの方法については、 他の答え


再びX Y問題に陥ったと思います。最初の質問はハッシュテーブルのフィルタリングに関するものでした。ハッシュテーブルを作成する前にフィルター処理する方が簡単であることがわかりました。質問に答えましたか?

いいえ、Yの問題は各キーをループし、@ briantistが助けてくれた値を使用していました。

私の目標は、タイムスタンプであるキー名をループし、キー名をタスク名およびトリガーとして使用してタスクをスケジュールすることです。

Group-Object -AsHashTable -AsString-editを使用してCSVファイルからハッシュテーブルを作成しています。ここで、HashTableを作成する前にCSVをフィルタリングすると、Pipelineまたはスクリプト

例として:

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

キー名をループして、キー名を表示できるようにしようとしています:

$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"}}

興味のあるキーから値を取得する方法がわかりません。

次の機能が見つかりましたが、キー名を手動で入力した場合のみです。両方のループをどのように結合するかわからないだけです。

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

ここにはいくつかのオプションがあります。

キーを列挙する:

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

キーと値のペアを列挙します(発見したが、効果的に使用していない可能性があります):

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

キー値の配列によるハッシュテーブルのフィルタリング(PSv3 +構文)に焦点を合わせることで briantistの有用な回答 を補完するには:

_# 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[]
_

さらに一致するキーと値のペアを処理するにするには、単に_%_(_ForEach-Object_)にパイプして、_$_.Key_および_$_.Value_(値)にアクセスします。

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

同等のコマンドパイプラインの代わりに、より効率的なforeach loop を使用:

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

注:PSv2の場合:
*演算子_-in_はサポートされていませんが、代わりにオペランド swapped で_-contains_を使用できます。
_'one', 'two' -contains $key_
*パイプラインで、_Where-Object { 'one', 'two' -contains $_.Key }_を使用します

サンプルハッシュテーブルを使用すると、次の結果が得られます。

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

出力のキーの順序が定義の順序と異なることに注意してください。 PSv3 +では、 ordered ハッシュテーブル(_[ordered] @{ ... }_)を作成して、定義の順序を保持できます。

上記で使用されるキーフィルタリング手法は、 not literal キー配列によるフィルタリングに制限されます。すべての(文字列)コレクションは、 different ハッシュテーブルの_-in_コレクションなど、_.Keys_オペランドのRHSとして機能します。

_# 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)" }
}
_

結果は、静的filter-keys配列を使用した例と同じです。

最後に、所定の場所でハッシュテーブルをフィルタリングするまたは new ハッシュテーブルを作成するフィルタリングされたエントリのみ

_# *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) }
} 
_

余談として:

_[System.Collections.DictionaryEntry]_のデフォルトの出力形式(したがって、ハッシュテーブル(_[System.Collections.Hashtable]_)は、Nameではなく列名Keyを使用します; Name alias property of Key PowerShell によって追加された( _[System.Collections.DictionaryEntry]_の一部ではない.NETタイプ定義 ;と検証
@{ one = 1 }.GetEnumerator() | Get-Member)。

9
mklement0