Словарь Swift - ключ к значению

Я использую быстрый словарь типа [UIImage: UIImage], и ​​я пытаюсь найти конкретный ключ для данного значения. В Objective-C я мог бы использовать allKeysForValue, но, похоже, такого метода для словаря Swift не существует. Что я должен использовать?

Ответ 1

Вы можете использовать allKeys(for:), если вы добавили к NSDictionary:

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

Ответ 2

Есть, насколько я знаю, нет встроенной функции 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: Как и в случае с Xcode 7 beta 2, теперь это можно сделать с методом расширения для словарей равных значений (спасибо Скорость воздушной скорости, чтобы сообщить об этом в комментарий):

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]

Ответ 3

Swift 3: более эффективный подход для специального случая биективных словарей

Если использование обратного словаря для поиска в словарях обратного словаря содержит биективный словарь с индивидуальной зависимостью между ключами и значениями, альтернативный подход к операции исчерпывающей коллекции filter будет использовать более быстрый подход короткого замыкания для поиска некоторого ключа, если он существует.

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

Ответ 4

Вот еще один подход, о котором я писал в в своем блоге. Он был протестирован против 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. Я писал о flatMap в моей функции более высокого порядка в Swift, если вам интересно.

Кроме того, поскольку мой метод является общим (благодаря наличию в классе Dictionary<Key,Value> generic), вам не нужно указывать его результат на тип ключа, который необходим при использовании allKeysForObject(_:) из NSDictionary.

Ответ 5

Версия Swift 2:

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

Ответ 6

Если вам нужно найти какой-либо ключ для значения (т.е. не все из них, если их больше одного, но только любое произвольное):

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, если такой ключ для значения отсутствует.

Ответ 7

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

Ответ 8

Это будет работать, если вам нужен какой-либо ключ для определенного значения. В моем случае был самый простой подход. Надеюсь, что это поможет:

Свифт 4. 1+

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

Ответ 9

Swift 5 без удлинителя

По какой-то причине подобные вопросы всегда вызывают ответы, которые используют extension. Если вам нужен ключ для определенного значения из единственного словаря или только одного раза и вы не хотите (и не должны) расширять весь объект 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)
    }

}