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<Key,Value>
通用类中),您不需要将其结果转换为键的类型,这在使用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 是字典元素,但key
和value
是字典元素,对吧?因为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字典获取值的关键的主要内容,如果未能解决你的问题,请参考以下文章