既存のコレクションの中では、System.Collections.Specialized.OrderedDictionary
が意図したものに近いと思われます。
OrderedDictionary Class (System.Collections.Specialized) | Microsoft Docs
言語サポートにより、インスタンスおよび初期化がしやすいのもポイントです。
ただしジェネリック非対応のため、型を指定できない点には注意が必要です。
powershell
1# サンプル
2
3# インスタンス。
4# [ordered] 属性をハッシュテーブルリテラルに付ければOK([ordered] で変数の型は指定できないので注意)
5$Dic = [ordered]@{}
6
7# 中身を指定して初期化。
8# ハッシュテーブルリテラルでそのまま指定すればOK。
9$Dic1 = [ordered]@{
10 a = 1
11 b = Get-Date
12 c = 'OrderedDictionary'
13 d = 1..10
14}
15<#
16Name Value
17---- -----
18a 1
19b 2019/03/13 XX:XX:XX
20c OrderedDictionary
21d {1, 2, 3, 4...}
22#>
「試したこと」のコードをOrderedDictionary
を使って書くと以下のようになります。
powershell
1$Dic = [Ordered]@{}
2
3$Ar = 0..9 |
4%{
5 [PSCustomObject]@{
6 Name = "Name$_"
7 Text = "Text_$_"
8 Disp = "テキスト_$_"
9 }
10}
11
12$Ar |
13%{
14 $Dic.Add($_.Name,$_)
15}
16
17
18Write-Host $Dic["Name5"].Name -ForegroundColor Red
19Write-Host $Dic[5].Name -ForegroundColor Red
その他参考
通常の辞書は、順番が保証されていません。
そのため、位置指定による中身へのアクセスが出来なくなっています。
わかりやすい例として、途中の要素を削除すると順序保証がされなくなります(このあたりの挙動は VBA の Scripting.Dictionary も同じ)。
powershell
1Using NameSpace System.Collections.Generic
2$dicN = [Dictionary[string,string]]::new()
3$dicN["a"] = "1"
4$dicN["b"] = "2"
5$dicN["c"] = "3"
6$dicN.Remove("b") > $null
7$dicN["d"] = "4"
8$dicN.Values
9<#
101
114 # 順番が変わる
123
13#>
この場合でもOrderedDictionary
なら順番を保証してくれます。
powershell
1$dicO = [ordered]@{}
2$dicO["a"] = "1"
3$dicO["b"] = "2"
4$dicO["c"] = "3"
5$dicO.Remove("b")
6$dicO["d"] = "4"
7$dicO.Values
8<#
91
103
114 # [2] の位置に追加される
12#>
参考記事
PowerShellのHashtableの並び替えを制御したい - tech.guitarrapc.cóm
190315 追記 KeyedCollection 継承クラス
KeyedCollection<TKey,TItem> Class (System.Collections.ObjectModel) | Microsoft Docs
KeyedCollection を適当に継承したクラスを作ってみましたが、一応動いているようです(自分の環境ではインテリセンスが不安定なのがちょっと気になりますが)。
KeyedCollection は抽象クラスなので、継承した上でGetKeyForItem
メソッドを実装して、各要素からキーを取得できるようする必要があります。
今回はサンプルとして、コンストラクタに与えられたスクリプトブロックからキーを算出させるようにしています(設計としては色々怖いのであくまでサンプル)。
powershell
1using namespace System.Collections.ObjectModel
2using namespace System.Management.Automation
3
4class MyKeyedList : KeyedCollection[string, PSCustomObject]
5{
6 # must override method.
7 hidden [string]GetKeyForItem([PSCustomObject]$TItem) {
8 return [string](ForEach-Object -InputObject $TItem -Process $this._keySelector)
9 }
10 hidden [scriptblock]$_keySelector
11
12 MyKeyedList(
13 # $_ 自動変数を使ってキーを算出するScriptBlcokを指定する。
14 [scriptblock]$KeySelector
15 ) : base() {
16 $this._keySelector = $KeySelector
17 }
18}
19
20# Name プロパティをキーとする
21$Dic = [MyKeyedList]::new({$_.Name})
22
23$Ar = 0..9 |
24%{
25 [PSCustomObject]@{
26 Name = "Name$_"
27 Text = "Text_$_"
28 Disp = "テキスト_$_"
29 }
30}
31
32$Ar |
33%{
34 $Dic.Add($_)
35}
36
37
38Write-Host $Dic["Name5"].Name -ForegroundColor Red
39Write-Host $Dic[5].Name -ForegroundColor Red