从结构检查nil值优雅填充字典

时间:2017-04-11 21:41:48

标签: swift dictionary

给定一个结构A,我希望用该结构中的值填充NSDictionary,前提是它们不是nil。
为此,我插入所有值,然后遍历字典,删除所有nil。是否有更优雅,简洁,不那么强力的解决方案?

struct A {
    var first:String?
    var second:String?
    var third:String?

    /* some init */
}

let a = A(/*some init*/)

var dictionary = [
    "first":a.first,
    "second":a.second,
    "third":a.third
]

for (key,value) in dictionary {
    if value == nil {
        dictionary.removeValue(forKey: key)
    }
}

2 个答案:

答案 0 :(得分:3)

拥有一个可选值的字典通常不是一个好主意。字典使用nil的赋值作为您要从字典中删除键/值对的指示。此外,字典查找返回一个可选值,所以如果你的值是可选的,你最终会得到一个需要两次打开的双重选项。

您可以使用以下事实:分配nil只需分配值即可删除字典条目以构建[String : String]字典。那些nil将不会进入字典,因此您不必删除它们:

struct A {
    var first: String?
    var second: String?
    var third: String?
}

let a = A(first: "one", second: nil, third: "three")

let pairs: [(String, String?)] = [
    ("first", a.first),
    ("second", a.second),
    ("third", a.third)
]

var dictionary = [String : String]()

for (key, value) in pairs {
    dictionary[key] = value
}

print(dictionary)
["third": "three", "first": "one"]

正如@Hamish在评论中指出的那样,你可以使用DictionaryLiteral {内部只是一个元组数组}来pairs,它允许你使用更干净的字典语法:

let pairs: DictionaryLiteral<String,String?> = [
    "first":  a.first,
    "second": a.second,
    "third":  a.third
]

所有其他代码保持不变。

注意:您可以编写DictionaryLiteral并让编译器推断出类型,但我看到Swift无法为大型字典文字编译或编译速度很慢。这就是为什么我在这里展示了显式类型的使用。

或者,您可以跳过Array的{​​{1}}或DictionaryLiteral,并直接指定值:

pairs
struct A {
    var first: String?
    var second: String?
    var third: String?
}

let a = A(first: "one", second: nil, third: "three")

var dictionary = [String : String]()

dictionary["first"] = a.first
dictionary["second"] = a.second
dictionary["third"] = a.third

print(dictionary)

答案 1 :(得分:1)

作为@vacawama says,您通常应该使用可选值来避开Dictionary类型,因为Dictionary API是围绕使用nil来表示缺少值的对于给定的密钥。因此,为Dictionary的{​​{1}}使用可选类型会导致混淆的双重包含选项,这通常会表现出不直观的行为。

另一个(更多的矫枉过正)解决方案是通过定义自己的'值展开'Value类型来直接利用字典文字。

ExpressibleByDictionaryLiteral

然后,您只需将此类型的实例传递给我们的extension Dictionary { /// A dictionary wrapper that unwraps optional values in the dictionary literal /// that it's created with. struct ValueUnwrappingLiteral : ExpressibleByDictionaryLiteral { typealias WrappedValue = Dictionary.Value fileprivate let base: [Key : WrappedValue] init(dictionaryLiteral elements: (Key, WrappedValue?)...) { var base = [Key : WrappedValue]() // iterate through the literal's elements, unwrapping the values, // and updating the base dictionary with them. for case let (key, value?) in elements { if base.updateValue(value, forKey: key) != nil { // duplicate keys are not permitted. fatalError("Dictionary literal may not contain duplicate keys") } } self.base = base } } init(unwrappingValues literal: ValueUnwrappingLiteral) { self = literal.base // simply get the base of the unwrapping literal. } } 初始化程序:

init(unwrappingValues:)