Swift词典获得价值的关键

时间:2014-11-30 21:51:27

标签: swift dictionary

我使用的是[UIImage:UIImage]类型的快速字典,我试图找到给定值的特定键。在Objective-C中我可以使用allKeysForValue,但是对于Swift字典似乎没有这样的方法。我该怎么用?

10 个答案:

答案 0 :(得分:59)

据我所知,没有内置的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开始,现在可以实现 使用可变值的字典的扩展方法 (感谢Airspeed Velocity让我在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]

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]

答案 1 :(得分:43)

<3> Swift 3:针对双向词典的特殊情况的更高效的方法

如果反向字典查找用例涵盖了一个双向字典,其中键和值之间具有一对一的关系,那么集合穷举meta: '<img src="/path/to/emoji.png">'操作的另一种方法是使用更快的短路方法来查找一些键,如果它存在。

filter

使用示例:

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

答案 2 :(得分:37)

如果您投放到allKeys(for:)

,则可以使用NSDictionary
let keys = (dict as NSDictionary).allKeys(for: image) as! [UIImage]

答案 3 :(得分:8)

这是我写的关于on my blog的另一种方法。它是针对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。我在Higher-order functions in Swift文章中写过关于flatMap的文章,如果您有兴趣的话。

另外,因为我的方法是通用的(因为在Dictionary<Key,Value>泛型类中),所以你不需要将其结果转换为键的类型,这在使用时是必需的来自allKeysForObject(_:)的{​​{1}}。

答案 4 :(得分:6)

Swift 2版本:

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

答案 5 :(得分: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

答案 6 :(得分:5)

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 :(得分:2)

不带扩展名的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)
    }

}

答案 8 :(得分:0)

如果您需要用于特定值的任何键,这将起作用。就我而言,这是最简单的方法。希望对您有所帮助:

Swift 4.1 +

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

答案 9 :(得分:0)

如果您不知道这些值是唯一的,则可以选择以下选项:

public extension Dictionary where Value: Equatable {
  /// The only key that maps to `value`.
  /// - Throws: `OnlyMatchError`
  func onlyKey(for value: Value) throws -> Key {
    try onlyMatch { $0.value == value } .key
  }
}
public extension Sequence {
  /// The only match for a predicate.
  /// - Throws: `OnlyMatchError`
  func onlyMatch(for getIsMatch: (Element) throws -> Bool) throws -> Element {
    guard let onlyMatch: Element = (
      try reduce(into: nil) { onlyMatch, element in
        switch ( onlyMatch, try getIsMatch(element) ) {
        case (_, false):
          break
        case (nil, true):
          onlyMatch = element
        case (.some, true):
          throw onlyMatchError.moreThanOneMatch
        }
      }
    ) else { throw onlyMatchError.noMatches }

    return onlyMatch
  }
}

/// An error thrown from a call to `onlyMatch`.
public enum OnlyMatchError: Error {
  case noMatches
  case moreThanOneMatch
}
XCTAssertEqual(
  try ["skunky": "monkey", "?": "?"].onlyKey(for: "?"),
  "?"
)