Swift字典:获取键以匹配给定的值

74

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

我使用的是一个类型为 [UIImage:UIImage] 的 Swift 字典,我想要根据给定的值找到对应的键。在 Objective-C 中,我可以使用 allKeysForValue 方法,但是在 Swift 字典中似乎没有这个方法。请问我该使用什么方法呢?
11个回答

80

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

1
太棒了。谢谢。 - Womble

68
据我所知,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评论中让我知道这一点):

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]

有没有办法返回字符串而不是数组的值?在我的设置中,每个键总是只有一个唯一值(它是一个日语到罗马字典)。 - sxflynn
只是想提一下,我在我的项目中已经使用了这种方法一段时间了,今天在分析性能时注意到它可能非常慢...正在寻找替代方案。 - jbm
1
@HashemAboonajmi:感谢您的编辑。但是,我决定恢复到以前的版本,因为我认为即使在Swift 3中,“allKeys(forValue:)”也是正确的。具有类似命名的现有方法包括“index(forKey:)”,“update(value: forKey:)”,“value(forKey:)”。 - Martin R

46

请注意,大多数答案在搜索之前会获取字典的全部键集。此答案使用first(where:)方法,在找到键后返回。

Swift 5(内联)

if let key = someDictionary.first(where: { $0.value == someValue })?.key {
    // use key
}

Swift 5 (扩展)

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

使用方法

let key = someDictionary.key(from: someValue)) // optional

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

6
太棒了!这应该是当前的正确答案。 - Adrian
@Adrian 注意,这个答案使用的方法与“已接受”的答案完全相同,而那个答案是在此之前3年发布的。然而,这个答案没有提到,应该小心使用它,明确知道它将产生一些键,特别是在字典中,其中几个键存储相同的值。 - dfrib

44
你可以使用 allKeys(for:),如果你将其转换为 NSDictionary:
let keys = (dict as NSDictionary).allKeys(for: image) as! [UIImage]

谢谢,这个方案很好,而且非常干净利落。 - mginn
只是一个微小的补充,我使用这段代码作为从字典中提取Int键的模式:let keys = (ItemDict as NSDictionary).allKeysForObject(orderItems[indexPath.row])然后你可以像这样访问:let someIntValue = keys[0].integerValue;非常好用,谢谢! - c0d3p03t
Swift 3:let keys =(dict as NSDictionary).allKeys(for:image)as![UIImage] - BitParser

15
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 的所需键


添加一些关于你的答案的解释。 - Pankaj Makwana

8

这里有另一种方法,我在我的博客上写过。它已经在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而不是filtermap。如果您感兴趣,我在我的Swift高阶函数文章中讲解了flatMap。此外,因为我的方法是通用的(由于位于Dictionary<Key,Value>通用类中),所以您不需要将其结果转换为键的类型,这在使用NSDictionaryallKeysForObject(_:)时是必要的。

谢谢您,我发现这是一种非常简洁的完成此任务的方法。 - alexwatever

5

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 呢? - JW.ZG
因为您正在映射字典,$0 是一个字典元素。$0.0 是键,$0.1 是值。 - Teo Sartori
抱歉,我不太明白您的意思。您说*$0是字典元素*,但是keyvalue才是字典元素,对吧?因为dictionary = [key:valule] - JW.ZG
你的意思是 $0 是字典中的第一个元素吗?就像 [firstKey:firstValue] 这样吗? - JW.ZG
1
在Swift中,字典被实现为通用集合。集合的内容通过迭代其元素来访问。在字典的情况下,这些元素被定义为键值对的元组。您可以使用索引访问元组的各个部分,因此$0.0对应于第一个(键),$0.1对应于第二个(与键相关联的值)。 - Teo Sartori

5
如果你需要找到某个值的一些键(即如果有多个,则不会是所有键,而只是任意一个):
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 将被返回。

1

如果您需要为特定值获取任何键,则此方法适用。在我的情况下,这是最简单的方法。希望它能帮到您:

Swift 4.1+

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

0
你可以通过筛选字典来找到与你要查找的值匹配的值,然后获取与该值配对的所有键。
FYI:在这个答案中,someValue代表你要查找的假设值。
dictionary.filter{$0.value == someValue}.keys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接