web-dev-qa-db-ja.com

Swift辞書は値のキーを取得

Swiftタイプ[UIImage:UIImage]の辞書を使用しています。特定の値の特定のキーを見つけようとしています。Objective-CではallKeysForValueを使用できますが、 Swift辞書のためのそのようなメソッドではないようです。私は何を使うべきですか?

49
mginn

NSDictionaryにキャストする場合は、allKeys(for:)を使用できます。

let keys = (dict as NSDictionary).allKeys(for: image) as! [UIImage]
40
vacawama

私の知る限り、特定の値のすべての辞書キーを取得する組み込みのSwift関数はありません。可能な実装は次のとおりです。

func allKeysForValue<K, V : Equatable>(dict: [K : V], val: V) -> [K] {
    return map(filter(dict) { $1 == val }) { $0.0 }
}

filterは、すべてのキーと値のペアを、指定された値を持つものに減らします。 mapは、(フィルタリングされた)キーと値のペアをキーのみにマップします。

使用例:

let dict = ["a" : 1, "b" : 2, "c" : 1, "d" : 2]
let keys = allKeysForValue(dict, 1)
println(keys) // [a, c]

Swift 2:のアップデート。Xcode7ベータ2の時点で、これは等値の辞書の拡張メソッドで実現できます( Airspeed Velocitya comment )でこれを認識します:

extension Dictionary where Value : Equatable {
    func allKeysForValue(val : Value) -> [Key] {
        return self.filter { $1 == val }.map { $0.0 }
    }
}

let dict = ["a" : 1, "b" : 2, "c" : 1, "d" : 2]
let keys = dict.allKeysForValue(1)
print(keys) // [a, c]

Swift 3 ::の更新

extension Dictionary where Value: Equatable {
    func allKeys(forValue val: Value) -> [Key] {
        return self.filter { $1 == val }.map { $0.0 }
    }
}

let dict = ["a" : 1, "b" : 2, "c" : 1, "d" : 2]
let keys = dict.allKeys(forValue: 1)
print(keys) // [a, c]
61
Martin R

Swift 3:全単射辞書の特殊なケースのためのより高性能なアプローチ

逆辞書検索のユースケースが、キーと値の間の1対1の関係を持つ全単射辞書を対象とする場合、コレクションを網羅するfilter操作の代替アプローチは、より高速な短絡アプローチを使用して見つけることです- someキー(存在する場合)。

extension Dictionary where Value: Equatable {
    func someKey(forValue val: Value) -> Key? {
        return first(where: { $1 == val })?.key
    }
}

使用例:

let dict: [Int: String] = [1: "one", 2: "two", 4: "four"]

if let key = dict.someKey(forValue: "two") { 
    print(key)
} // 2
45
dfri

私のブログで について書いた別のアプローチがあります。 Swift 2.2。

extension Dictionary where Value: Equatable {
  /// Returns all keys mapped to the specified value.
  /// ```
  /// let dict = ["A": 1, "B": 2, "C": 3]
  /// let keys = dict.keysForValue(2)
  /// assert(keys == ["B"])
  /// assert(dict["B"] == 2)
  /// ```
  func keysForValue(value: Value) -> [Key] {
    return flatMap { (key: Key, val: Value) -> Key? in
      value == val ? key : nil
    }
  } 
}

flatMapに続いてfilterの代わりにmapを使用するため、指定された値にマッピングされたすべてのキーを生成するこのスレッドに投稿される最も効率的な実装です。興味があるなら、私は Swiftの高階関数 の記事でflatMapについて書きました。

また、私のメソッドはジェネリック(Dictionary<Key,Value>ジェネリッククラスにあるため)であるため、その結果をキーの型にキャストする必要はありません。これは、NSDictionaryからallKeysForObject(_:)を使用する場合に必要です。

8
Josh Smith
let dict = ["key1":2,"key2":6,"key3":8,"key4":8]
let searchingValue = 8
let b = dict.filter {$0.value == searchingValue}
let a = b.keys.first

bはマップを提供しますsearchingValueこれは["key4":8,"key3":8]

b.keys.firstは、フィルタリングされたすべてのキーの最初の要素であるgを提供します

aは値の必須キーです8

7
Learner

値のsomeキーを見つける必要がある場合(つまり、複数ある場合はallではなく、任意の1つだけ):

extension Dictionary where Value: Equatable {

    func someKeyFor(value: Value) -> Key? {

        guard let index = indexOf({ $0.1 == value }) else {
            return nil
        }

        return self[index].0

    }

}

値にそのようなキーがない場合、上記はnilを返します。

6
Anton Bronnikov

Swift 2バージョン:

func allKeysForValue<K, V : Equatable>(dict: [K : V], val: V) -> [K] {
    return dict.filter{ $0.1 == val }.map{ $0.0 }
}
6
Teo Sartori

Swift 5拡張子なし

何らかの理由で、これらの種類の質問は、extensionを使用する回答を常に引き出します。単一のディクショナリまたは一度だけの特定の値のキーが必要であり、1回限りの場合にFoundationオブジェクト全体を拡張したくない(したくない)場合は、手動で実行します。

var imageDictionary = [UIImage: UIImage]()

func getKey(for value: UIImage) {

    if let entry = imageDictionary.first(where: { (_, v) -> Bool in
        return v == value
    }) {
        print(entry.key)
    }

}
3
bsod

これは、特定の値のキーが必要な場合に機能します。私の場合、最も簡単なアプローチでした。それが役立つことを願っています:

Swift 4.1+

extension Dictionary where Key == String, Value: Equatable {
    func key(for value: Value) -> Key? {
        return compactMap { value == $1 ? $0 : nil }.first
    }
}
1
davebcn87