通常はDictionaryにkeyを投げて対応するvalueを取得しますが、
valueを投げて対応するkey(keys)を取得してみます。
実はObjective-Cの時から、NSDictionary
クラスに、 allKeysForObject という、valueを投げて対応するkeyの配列を返してくれるメソッドがあるので、それに倣って書いてみます。
実装
extension Dictionary where Value: Equatable {
func allKeysForValue(value: Value) -> [Key] {
return self.filter({ $0.1 == value }).map({ $0.0 })
// return self.flatMap({ $0.1 == value ? $0.0 : nil }) // こっちでもok
}
func keyForValue(value: Value) -> Key? {
return allKeysForValue(value).first
}
}
Filter→Mapが素直な感じですが、計算量が結構大きくなる可能性があるので、
flatMapで一発で済ませるのもアリです。
こんな感じで取得できます。
let list = [
"Apple" : 10001,
"Banana" : 10002,
"Candy" : 10003,
]
//------
print(list.allKeysForValue(10001)) // ["Apple"]
print(list.keyForValue(10002)) // Optional("Banana")
print(list.keyForValue(10010)) // nil
注意としては、keyは重複しないので、keyを投げて取得できるvalueは一意に定まりますが、valueはそうとは限らないので、対応するkeyが複数取得できる場合があります。例えば、
let list = [
"Apple" : 10001,
"Banana" : 10002,
"Candy" : 10003,
"Desert" : 10001,
]
に対して10001
を投げてみると、["Apple","Desert"]
で返却されます。
その場合のkeyForValue
は最初にヒットした方を返すようにしているので、そっちを使うと"Desert"
は見逃すことになります。
一意に定められるのか、複数ありえるのかで使用する関数を変えれば良いかと思います。
余談
こういうのが必要!ってなったら、無理にDictionaryのKeyとValueでやろうとしないで、 素直にstruct
で構造体を作ってあげた方が色々と処理しやすいかと思います。