Swift字典获取值的关键

Posted

技术标签:

【中文标题】Swift字典获取值的关键【英文标题】:Swift dictionary get key for value 【发布时间】:2014-11-30 21:51:26 【问题描述】:

我正在使用 [UIImage:UIImage] 类型的 swift 字典,并且我正在尝试为给定值查找特定键。在 Objective-C 中,我可以使用 allKeysForValue,但 Swift 字典似乎没有这样的方法。我应该使用什么?

【问题讨论】:

【参考方案1】:

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

【讨论】:

太棒了。谢谢。【参考方案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 开始,现在可以实现 具有等值字典的扩展方法 (感谢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]

【讨论】:

有没有办法将值作为字符串而不是数组返回?在我的设置中,每个键始终只有一个唯一值(它是从日文到罗马字的字典)。 只是想我会提到我在我的项目中使用这种方法有一段时间了,今天在分析时注意到它可能非常慢...寻找替代品。 @HashemAboonajmi:感谢您的编辑。但是,我决定恢复到以前的版本,因为我认为即使在 Swift 3 中allKeys(forValue:) 也是正确的。具有类似命名的现有方法是index(forKey:)update(value: forKey)value(forKey:)【参考方案3】:

如果您转换为NSDictionary,则可以使用allKeys(for:)

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

【讨论】:

谢谢,效果很好,而且是一个很好的干净解决方案。 只是一个小小的补充,我用这段代码作为一个模式从字典中提取一个 Int 键:let keys = (ItemDict as NSDictionary).allKeysForObject(orderItems[indexPath.row]) 然后你可以访问:let someIntValue = keys[0].integerValue; 像梦一样工作,谢谢!跨度> 斯威夫特 3:let keys = (dict as NSDictionary).allKeys(for: image) as! [UIImage]【参考方案4】:

了解这些答案中的大多数会在搜索字典之前获取字典的整个键集。此答案使用找到密钥后返回的first(where:) 方法。

Swift 5(内联)

let someValue = UIImage()

if let key = someDictionary.first(where:  $0.value == someValue )?.key 
    print(key)

Swift 5(扩展)

extension Dictionary where Value: Equatable 
    func key(from value: Value) -> Key? 
        return self.first(where:  $0.value == value )?.key
    


print(someDictionary.key(from: someValue)) // optional

if let key = someDictionary.key(from: someValue) 
    print(key) // non-optional

【讨论】:

太棒了!这应该是当前的正确答案。 @Adrian 请注意,此答案使用与 accepted 答案完全相同的方法,该答案在此答案之前 3 年发布。然而,这个答案没有提到应该小心使用它,明确知道它会产生 some 键,特别是在几个键存储相同值的字典中。【参考方案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

的所需键

【讨论】:

添加一些关于你的答案的解释【参考方案6】:

这是另一种方法,我写了关于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&lt;Key,Value&gt; 通用类中),您不需要将其结果转换为键的类型,这在使用NSDictionary 中的allKeysForObject(_:) 时是必需的。

【讨论】:

谢谢你,我发现这是完成这项任务的一种非常干净的方式。【参考方案7】:

Swift 2 版本:

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

【讨论】:

为什么是$0.1$0.0 而不是$0$1 因为您正在映射字典,所以 $0 是字典元素。 $0.0 是键,$0.1 是值。 对不起,我不明白你的意思。您说$0 是字典元素,但keyvalue 是字典元素,对吧?因为dictionary = [key:valule]. 你的意思是$0 是字典中的第一个元素吗?喜欢[firstKey:firstValue] 在 Swift 中字典被实现为通用集合。集合的内容是通过迭代其元素来访问的。在字典的情况下,这些元素被定义为键值对的元组。您可以使用索引访问元组的各个部分,因此 $0.0 对应于第一个(键),$0.1 对应于第二个(与键相关的值)。【参考方案8】:

如果您需要为一个值找到 some 键(即,如果有多个,则不是 all,而是任意一个):

extension Dictionary where Value: Equatable 

    func someKeyFor(value: Value) -> Key? 

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

        return self[index].0

    


如果值没有这样的键,Above 返回nil

【讨论】:

【参考方案9】:

如果您需要特定值的任何键,这将起作用。在我的情况下是最简单的方法。希望对你有帮助:

斯威夫特 4.1+

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

【讨论】:

【参考方案10】:

如果您不知道这些值是唯一的,这是一个选项:

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: "?"),
  "?"
)

【讨论】:

以上是关于Swift字典获取值的关键的主要内容,如果未能解决你的问题,请参考以下文章

如何使用swift获取字典中的索引值

如何制作包含特定值的 Swift 字典?

Swift - 具有实现通用协议的值的 Typealias 字典

Swift:如何使用 Eureka 表单生成器获取表单值?

Swift下面字典(json)和模型的转换

使用 Swift 将具有相同类型的字典分组到具有完整键和值的数组中