我使用的是[UIImage:UIImage]类型的快速字典,我试图找到给定值的特定键。在Objective-C中我可以使用allKeysForValue,但是对于Swift字典似乎没有这样的方法。我该怎么用?
答案 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)
如果反向字典查找用例涵盖了一个双向字典,其中键和值之间具有一对一的关系,那么集合穷举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)
如果您需要用于特定值的任何键,这将起作用。就我而言,这是最简单的方法。希望对您有所帮助:
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: "?"),
"?"
)