index - swift dictionary values




Swift dictionary get key for value (6)

I'm using a swift dictionary of type [UIImage:UIImage], and I'm trying to find a specific key for a given value. In Objective-C I could use allKeysForValue, but there appears to be no such method for a Swift dictionary. What should I be using?


Swift 3: a more performant approach for the special case of bijective dictionaries

If the reverse dictionary lookup use case covers a bijective dictionary with a one to one relationship between keys and values, an alternative approach to the collection-exhaustive filter operation would be using a quicker short-circuiting approach to find some key, if it exists.

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

Example usage:

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

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

Here's another approach, which I wrote about on my blog . It was tested against 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
    }
  } 
}

It's the most efficient implementation posted to this thread that yields all keys mapped to a specified value, because it uses flatMap , instead of filter and then map . I wrote about flatMap in my Higher-order functions in Swift article, if you're interested.

Also, because my method is generic (by virtue of being in the Dictionary<Key,Value> generic class) you don't need to cast its result to the key's type, which is necessary when using allKeysForObject(_:) from NSDictionary .


The Swift 2 version:

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

There is, as far as I know, no built-in Swift function to get all dictionary keys for a given value. Here is a possible implementation:

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

The filter reduces all key-value pairs to those with the given value. The map maps the (filtered) key-value pairs to the keys alone.

Example usage:

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

Update for Swift 2: As of Xcode 7 beta 2, this can now be achieved with an extension method for dictionaries of equatable values (thanks to Airspeed Velocity to make me aware of this in a 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]

Update for 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]

You can use allKeys(for:) if you cast to NSDictionary :

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

Swift 5 without extension

For whatever reason these kinds of questions always elicit answers that use extension . If you need the key for a specific value from just a single dictionary or just a single time and don't want to (and should not) extend an entire Foundation object for a one-off case, do it manually:

var imageDictionary = [UIImage: UIImage]()

func getKey(for value: UIImage) {

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

}




dictionary