順番つきの Dictionary な OrderedDictionary が Swift にやってきた

3 min read読了の目安(約3400字

TL;DR

// Dictionary では要素の順番は保証されない
let northKantoDictionary = [08 : "茨城県", 09 : "栃木県", 10 : "群馬県", 11 : "埼玉県", 12 : "千葉県", 13 : "東京都", 14 : "神奈川県"]
// [13: "東京都", 10: "群馬県", 11: "埼玉県", 14: "神奈川県", 12: "千葉県", 8: "茨城県", 9: "栃木県"]

// OrderedDictionary では要素の順番が保証される
let northKantoOrderedDictionary: OrderedDictionary = [08 : "茨城県", 09 : "栃木県", 10 : "群馬県", 11 : "埼玉県", 12 : "千葉県", 13 : "東京都", 14 : "神奈川県"]
// [8: 茨城県, 9: 栃木県, 10: 群馬県, 11: 埼玉県, 12: 千葉県, 13: 東京都, 14: 神奈川県]

関連

https://zenn.dev/treastrain/articles/e06efd3ec58ce2

Dictionary は要素の順番を保証しない

ISO 3166-2:JP (JIS X 0401) 都道府県コードとそれに対応した都道府県名の Dictionary を作ってみます。

// ISO 3166-2:JP (JIS X 0401) 都道府県コード
var kantoDictionary = [
    08 : "茨城県",
    09 : "栃木県",
    10 : "群馬県",
    11 : "埼玉県",
    12 : "千葉県",
    13 : "東京都",
]

// Dictionary に要素を追加
northKantoDictionary[14] = "神奈川県"

これを都道府県コード順に一度に取り出してみます。

print(northKantoDictionary)
// [11: "埼玉県", 12: "千葉県", 14: "神奈川県", 13: "東京都", 9: "栃木県", 10: "群馬県", 8: "茨城県"]

for prefecture in northKantoDictionary {
    print(prefecture)
}
// (key: 11, value: "埼玉県")
// (key: 12, value: "千葉県")
// (key: 14, value: "神奈川県")
// (key: 13, value: "東京都")
// (key: 9, value: "栃木県")
// (key: 10, value: "群馬県")
// (key: 8, value: "茨城県")

Dictionary は要素の順番を保証しないため、実行のたびに print(northKantoDictionary) の出力結果が変わってしまいます。

しかし、ISO 3166-2:JP (JIS X 0401) に合わせて順番は保証したいところ…

順番つきの DictionaryOrderedDictionary

順番つきの Dictionary なを使いたいときは Collections にある OrderedDictionary を用います。

https://github.com/apple/swift-collections
// Swift Package Manager で Collections を導入

import Collections // または import OrderedCollections

var northKantoOrderedDictionary: OrderedDictionary = [
    08 : "茨城県",
    09 : "栃木県",
    10 : "群馬県",
    11 : "埼玉県",
    12 : "千葉県",
    13 : "東京都",
]

print(northKantoOrderedDictionary)
// [8: 茨城県, 9: 栃木県, 10: 群馬県, 11: 埼玉県, 12: 千葉県, 13: 東京都]

// OrderedDictionary に要素を追加
northKantoOrderedDictionary[14] = "神奈川県"

print(northKantoOrderedDictionary)
// [8: 茨城県, 9: 栃木県, 10: 群馬県, 11: 埼玉県, 12: 千葉県, 13: 東京都, 14: 神奈川県]

keyHashable に準拠しているので、key でソート等も行えます。

var northKantoOrderedDictionary: OrderedDictionary = [
    13 : "東京都",
    11 : "埼玉県",
    12 : "千葉県",
    09 : "栃木県",
    10 : "群馬県",
    14 : "神奈川県",
    08 : "茨城県",
]

print(northKantoOrderedDictionary)
// [13: 東京都, 11: 埼玉県, 12: 千葉県, 9: 栃木県, 10: 群馬県, 14: 神奈川県, 8: 茨城県]
northKantoOrderedDictionary.sort()
print(northKantoOrderedDictionary)
// [8: 茨城県, 9: 栃木県, 10: 群馬県, 11: 埼玉県, 12: 千葉県, 13: 東京都, 14: 神奈川県]

添字によるアクセスは、そのままでは key によるアクセスとなり、要素の順番でアクセスするには elements プロパティを使います。

// key でアクセス
print(northKantoOrderedDictionary[8]) // Optional("茨城県")

// 順番でアクセス
print(northKantoOrderedDictionary.elements[0].value) // 茨城県

/* ---------------------------------------- */

print(type(of: northKantoOrderedDictionary))
// OrderedDictionary<Int, String>

print(type(of: northKantoOrderedDictionary.elements))
// OrderedDictionary<Int, String>.Elements

print(type(of: northKantoOrderedDictionary.elements[0]))
// (key: Int, value: String)

参考文献