sorta kinda...

主にAWS関連ですが、これに限らずいろいろ勉強したことや思ったことを書いていきます。

PowerShell の連想配列ですべてを逆から処理する方法

PowerShell ムズカシイデス。那須です。

PowerShell連想配列に入ってるものを順に処理したり順番関係なく処理したりするのは簡単なんですが、逆から処理するのっていいやり方がなくて困ってたりしませんか? そもそも逆順で処理するシーンがあまりないのかもしれませんね。

スクリプトの作りが悪い、という話もありますが、極力シンプルにかつ使い回せるインフラのスクリプトを作りたくてこんな悩みを持っていました。 例えばサービスの起動停止スクリプトで、設定ファイルに起動する順番通りにサービス名を書いてもらうけど、逆順で同じようなことを書きてほしくないですよね? そもそも二度手間ですし。 今回は無理やりなんとかしたので、それを忘れないために書き残しておきます。

 

そもそも連想配列の順番って固定できるの?

とりあえず何も考えずに連想配列を作って表示してみましょう。

PS C:\> $hashtable = @{AAA = "aaa", "bbb"; BBB = "ccc","ddd" }
PS C:\> $hashtable

Name                           Value
----                           -----
BBB                            {ccc, ddd}
AAA                            {aaa, bbb}

とまあ、キーが逆になってますね。 値の順番はそのままですが。

で、キー AAA から処理したい場合は、連想配列の初期化時に [ordered] をつけます。

PS C:\> $hashtable = [ordered]@{AAA = "aaa", "bbb"; BBB = "ccc","ddd" }
PS C:\> $hashtable

Name                           Value
----                           -----
AAA                            {aaa, bbb}
BBB                            {ccc, ddd}

これでとりあえず順番は指定できそうです。

 

逆順にする何かがあるのでは?

と思いましたので、リストならどうするのか調べてみると Reverse で簡単にできることがわかりました。

PS C:\> $List = @("aaa", "bbb", "ccc", "ddd")
PS C:\> $List
aaa
bbb
ccc
ddd
PS C:\> [array]::Reverse($List)
PS C:\> $List
ddd
ccc
bbb
aaa

案外連想配列でもできるんじゃね?って思ってやってみました。

PS C:\> [array]::Reverse($hashtable)
PS C:\> $hashtable

Name                           Value
----                           -----
AAA                            {aaa, bbb}
BBB                            {ccc, ddd}

何も起こりませんでした… 続きまして hashtable 指定でやってみると、

PS C:\> [hashtable]::Reverse($hashtable)
[System.Collections.Hashtable]'Reverse' という名前のメソッドが含まれないため、メソッドの呼び出しに失敗しました。
発生場所 行:1 文字:1
+ [hashtable]::Reverse($hashtable)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) []、RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

そんなことできません!とのことです。 他にもいろいろ検索してみたんですが、これだ!って解決策がなかったので、普通に頭で考えてたソートをコード化しました。 $hashtable は [ordered] 指定してください。

function hashtable逆から処理する {
    param([System.Collections.Specialized.OrderedDictionary]$hashtable)
    $keyList = @()
    foreach ($key in $hashtable.Keys) {
        $keyList += $key
    }
    [array]::Reverse($keyList)

    foreach ($key in $keyList) {
        $contentList = @()
        foreach ($content in $hashtable[$key]) {
            $contentList += $content
        }
        [array]::Reverse($contentList)
        $hashtable[$key] = $contentList
    }

    foreach ($key in $keyList) {
        foreach ($content in $hashtable[$key]) {
            処理
        }
    }
}

要は、

  • キーを逆順ソートして別のリストに入れる
  • 値も取り出して逆順ソートしてリストに入れたもので定義し直す
  • 逆順ソートしたキーのリストをキーとして foreach する

だけです。 私の小さい脳みそではこうするしかありませんでした。

 

実は他にもっと簡単なやり方あるのでは?

と今でも思ってたりします。 ので、もしご存知の方がいたら鼻で笑いながらでもいいのでツッコミいただければ嬉しいです!