Swift:如何从Dictionary中删除空值?

我是Swift的新手,我在从JSON文件中过滤NULL值并将其设置为Dictionary时遇到问题。 我从服务器获取空值的JSON响应,它崩溃了我的应用程序。

这是JSON响应:

"FirstName": "Anvar", "LastName": "Azizov", "Website": null, "About": null, 

我将非常感谢您的帮助来处理它。

UPD1:此刻我决定以下一个方式做到这一点:

 if let jsonResult = responseObject as? [String: AnyObject] { var jsonCleanDictionary = [String: AnyObject]() for (key, value) in enumerate(jsonResult) { if !(value.1 is NSNull) { jsonCleanDictionary[value.0] = value.1 } } } 

您可以创建一个包含相应值为nil的键的数组:

 let keysToRemove = dict.keys.array.filter { dict[$0]! == nil } 

然后循环遍历该数组的所有元素并从字典中删除键:

 for key in keysToRemove { dict.removeValueForKey(key) } 

更新2017.01.17

如评论中所解释的那样,力展开算子虽然安全,但有点难看。 可能有其他几种方法可以实现相同的结果,同一方法的更好看方式是:

 let keysToRemove = dict.keys.filter { guard let value = dict[$0] else { return false } return value == nil } 

我最后在Swift 2中得到了这个:

 extension Dictionary where Value: AnyObject { var nullsRemoved: [Key: Value] { let tup = filter { !($0.1 is NSNull) } return tup.reduce([Key: Value]()) { (var r, e) in r[e.0] = e.1; return r } } } 

对于Swift 3,答案相同:

 extension Dictionary { /// An immutable version of update. Returns a new dictionary containing self's values and the key/value passed in. func updatedValue(_ value: Value, forKey key: Key) -> Dictionary { var result = self result[key] = value return result } var nullsRemoved: [Key: Value] { let tup = filter { !($0.1 is NSNull) } return tup.reduce([Key: Value]()) { $0.0.updatedValue($0.1.value, forKey: $0.1.key) } } } 

Swift 4中,事情变得容易多了。 只需直接使用Dictionary的filter

 jsonResult.filter { !($0.1 is NSNull) } 

或者,如果您不想删除相关密钥,则可以执行以下操作:

 jsonResult.mapValues { $0 is NSNull ? nil : $0 } 

这将用nil替换NSNull值而不是删除键。

假设您只想从字典中过滤掉任何NSNull值,这可能是更好的方法之一。 就我现在所知,它可以防范Swift 3:

(感谢AirspeedVelocity的扩展,翻译成Swift 2)

 import Foundation extension Dictionary { /// Constructs [key:value] from [(key, value)] init (_ seq: S) { self.init() self.merge(seq) } mutating func merge (seq: S) { var gen = seq.generate() while let (k, v) = gen.next() { self[k] = v } } } let jsonResult:[String: AnyObject] = [ "FirstName": "Anvar", "LastName" : "Azizov", "Website" : NSNull(), "About" : NSNull()] // using the extension to convert the array returned from flatmap into a dictionary let clean:[String: AnyObject] = Dictionary( jsonResult.flatMap(){ // convert NSNull to unset optional // flatmap filters unset optionals return ($0.1 is NSNull) ? .None : $0 }) // clean -> ["LastName": "Azizov", "FirstName": "Anvar"] 

建议使用此方法,展平可选值并与Swift 3兼容

String键,可选AnyObject? nil值的值字典:

 let nullableValueDict: [String : AnyObject?] = [ "first": 1, "second": "2", "third": nil ] // ["first": {Some 1}, "second": {Some "2"}, "third": nil] 

删除nil值并转换为非可选值字典

 nullableValueDict.reduce([String : AnyObject]()) { (dict, e) in guard let value = e.1 else { return dict } var dict = dict dict[e.0] = value return dict } // ["first": 1, "second": "2"] 

由于删除了swift 3中的var参数,因此需要重新声明var dict = dict ,因此对于swift 2,1,它可能是;

 nullableValueDict.reduce([String : AnyObject]()) { (var dict, e) in guard let value = e.1 else { return dict } dict[e.0] = value return dict } 

斯威夫特4,将是;

 let nullableValueDict: [String : Any?] = [ "first": 1, "second": "2", "third": nil ] let dictWithoutNilValues = nullableValueDict.reduce([String : Any]()) { (dict, e) in guard let value = e.1 else { return dict } var dict = dict dict[e.0] = value return dict } 

由于Swift 4为类Dictionary提供方法reduce(into:_:) ,您可以使用以下函数从Dictionary删除nil-values:

 func removeNilValues(dict:Dictionary) -> Dictionary { return dict.reduce(into: Dictionary()) { (currentResult, currentKV) in if let val = currentKV.value { currentResult.updateValue(val, forKey: currentKV.key) } } } 

你可以这样测试它:

 let testingDict = removeNilValues(dict: ["1":nil, "2":"b", "3":nil, "4":nil, "5":"e"]) print("test result is \(testingDict)") 

我只需解决这个问题,一般情况下NSNulls可以嵌套在任何级别的字典中,甚至可以是数组的一部分:

 extension Dictionary where Key == String, Value == Any { func strippingNulls() -> Dictionary { var temp = self temp.stripNulls() return temp } mutating func stripNulls() { for (key, value) in self { if value is NSNull { removeValue(forKey: key) } if let values = value as? [Any] { var filtered = values.filter {!($0 is NSNull) } for (index, element) in filtered.enumerated() { if var nestedDict = element as? [String: Any] { nestedDict.stripNulls() if nestedDict.values.count > 0 { filtered[index] = nestedDict as Any } else { filtered.remove(at: index) } } } if filtered.count > 0 { self[key] = filtered } else { removeValue(forKey: key) } } if var nestedDict = value as? [String: Any] { nestedDict.stripNulls() if nestedDict.values.count > 0 { self[key] = nestedDict as Any } else { self.removeValue(forKey: key) } } } } 

}

我希望这对其他人有帮助我欢迎改进!

(注意:这是Swift 4)

以下是解决方案,当JSONsub-dictionaries 。 这将遍历所有dictionariesJSON sub-dictionaries并从JSON删除NULL (NSNull) key-value对。

 extension Dictionary { func removeNull() -> Dictionary { let mainDict = NSMutableDictionary.init(dictionary: self) for _dict in mainDict { if _dict.value is NSNull { mainDict.removeObject(forKey: _dict.key) } if _dict.value is NSDictionary { let test1 = (_dict.value as! NSDictionary).filter({ $0.value is NSNull }).map({ $0 }) let mutableDict = NSMutableDictionary.init(dictionary: _dict.value as! NSDictionary) for test in test1 { mutableDict.removeObject(forKey: test.key) } mainDict.removeObject(forKey: _dict.key) mainDict.setValue(mutableDict, forKey: _dict.key as? String ?? "") } if _dict.value is NSArray { let mutableArray = NSMutableArray.init(object: _dict.value) for (index,element) in mutableArray.enumerated() where element is NSDictionary { let test1 = (element as! NSDictionary).filter({ $0.value is NSNull }).map({ $0 }) let mutableDict = NSMutableDictionary.init(dictionary: element as! NSDictionary) for test in test1 { mutableDict.removeObject(forKey: test.key) } mutableArray.replaceObject(at: index, with: mutableDict) } mainDict.removeObject(forKey: _dict.key) mainDict.setValue(mutableArray, forKey: _dict.key as? String ?? "") } } return mainDict as! Dictionary } } 

您可以通过以下函数将空值替换为空字符串。

 func removeNullFromDict (dict : NSMutableDictionary) -> NSMutableDictionary { let dic = dict; for (key, value) in dict { let val : NSObject = value as! NSObject; if(val.isEqual(NSNull())) { dic.setValue("", forKey: (key as? String)!) } else { dic.setValue(value, forKey: key as! String) } } return dic; }