确定Swift字典是否包含键并获取其任何值


260

我当前正在使用以下(笨拙的)代码段来确定(非空的)Swift字典是否包含给定的键并从同一字典中获取一个(任何)值。

如何将其更优雅地放在Swift中?

// excerpt from method that determines if dict contains key
if let _ = dict[key] {
    return true
}
else {
    return false
}

// excerpt from method that obtains first value from dict
for (_, value) in dict {
    return value
}

indexForKey如果您觉得它更清晰,更明确,则可以使用;stackoverflow.com/a/29299943/294884
Fattie

很多时候,你想要什么基本上是: cityName:String = dict["city"] ?? ""?? ""这里基本上意味着“如果没有这样的键,返回空白”。
Fattie

Answers:


480

您不需要任何特殊的代码即可执行此操作,因为这已是字典的功能。提取时,dict[key]知道字典是否包含键,因为返回的Optional不nil包含(并且包含值)。

因此,如果您只想回答字典是否包含密钥的问题,请询问:

let keyExists = dict[key] != nil

如果您需要该值并且知道字典包含键,请说:

let val = dict[key]!

但是,如果像通常发生的那样,您不知道它包含密钥-您想获取它并使用它,但前提是它存在,则使用类似以下内容的代码if let

if let val = dict[key] {
    // now val is not nil and the Optional has been unwrapped, so use it
}

6
我不懂 我只是获得了一个值(两次)。您还想要什么?
马特2015年

没有“第一价值”之类的东西。字典是无序的。如果只需要值而没有键,请说dict.values
马特2015年

1
请注意,因为它dict.values是不透明的。您可以循环浏览,仅此而已。(好吧,这还不是全部,但是让我很幽默。)如果您希望将它具体化为Array,请使用dict.values.array
马特2015年

1
@bubakazouba尝试一下:let d = ["hey":"ho"]; let s = d["hey"]; print(s)这是一个可选的方法,就像往常一样。
马特2015年

1
@Kross这是一个非常深刻的问题,因此请单独询问。
马特

68

为什么不简单地检查dict.keys.contains(key)dict[key] != nil如果值为零,则检查将不起作用。以字典[String: String?]为例。


2
或者if let val = dict[key]可以if let val = dict[key] as? String在这种情况下使用,而不仅仅是编写。
Okhan Okbay,

.keys.contains不能帮助区分键是否存在或值是否为nil。也许在较早的版本中?不为我在迅速4.工作
罗文贡捷

8
这可能非常浪费,因为(1)调用dict.keys创建具有所有键的数组,然后(2)依次检查每个键,直到找到一个(或一个都不找到!)。我知道您正在尝试解决a的情况[String: String?],但是使用该解决方案要非常小心...
查尔斯

3
正如@charles所提到的,这将消除使用字典提供的快速查找的好处,因此我建议您不要使用该字典,但绝对是有效的选择。
businesscasual

4
永远不要使用这种方法,因为它具有O(n)的复杂度,而不是直接字典访问的理论(取决于散列函数的实现)O(1)。
Krypt

45

let keyExists = dict[key] != nil如果Dictionary包含键但值为nil,则可接受的答案将不起作用。

如果要确保Dictionary根本不包含密钥,请使用此键(在Swift 4中进行了测试)。

if dict.keys.contains(key) {
  // contains key
} else { 
  // does not contain key
}

3
这和韩的回答是一样的。
Declan McKenna

1
== nil即使字典具有可选值,检查也可以。这是因为查找结果包装为Optional。另一方面,要检查查找的值是否真实nil而不是不存在,可以使用== .some(nil)
jedwidz

1
与其他方法的O(1)查找相比,我将增加使用此方法的效率。我相信这是O(n)的查找
阿尔贝托·维加

1
@ AlbertoVega-MSFT是O(1)。另请参见:github.com/apple/swift-evolution/blob/master/proposals / ...是什么让您认为它是O(n)
亚历山大-恢复莫妮卡

1
Dictionary.Keys.contains(...)函数的文档在这里说它很O(n)复杂,n序列的长度在哪里。
阿迪尔·侯赛因

5

看起来您从@matt获得了所需的东西,但是如果您想要一种快速的方法来获取键的值,或者如果该键不存在,则只是第一个值:

extension Dictionary {
    func keyedOrFirstValue(key: Key) -> Value? {
        // if key not found, replace the nil with 
        // the first element of the values collection
        return self[key] ?? first(self.values)
        // note, this is still an optional (because the
        // dictionary could be empty)
    }
}

let d = ["one":"red", "two":"blue"]

d.keyedOrFirstValue("one")  // {Some "red"}
d.keyedOrFirstValue("two")  // {Some "blue"}
d.keyedOrFirstValue("three")  // {Some "red”}

请注意,不能保证您将实际获得第一个值,在这种情况下,它只是返回“ red”。


1
很好地使用??运算符代替了我的便捷解决方案,但作为扩展,默认值可能表示数据不安全或意外行为。这听起来Dictionary应该是一个具体的子类。如果nil退货不包括针对特定情况的功能,那么您多久需要第一个值?
NoodleOfDeath '16


0

我的缓存实现的解决方案是存储可选的NSAttributedString:

public static var attributedMessageTextCache    = [String: NSAttributedString?]()

    if attributedMessageTextCache.index(forKey: "key") != nil
    {
        if let attributedMessageText = TextChatCache.attributedMessageTextCache["key"]
        {
            return attributedMessageText
        }
        return nil
    }

    TextChatCache.attributedMessageTextCache["key"] = .some(.none)
    return nil

0

这是在Swift 3上对我有用的东西

let _ = (dict[key].map { $0 as? String } ?? "")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.