给定一个结构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)
}
}
答案 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:)