from dictionaries array ios json swift null nsdictionary

ios - dictionaries - Swift: ¿Cómo eliminar un valor nulo de Dictionary?



nsdictionary swift 4 (6)

Soy nuevo en Swift y tengo un problema con el filtrado de valores NULL del archivo JSON y su configuración en Diccionario. Recibo una respuesta json del servidor con valores nulos y bloquea mi aplicación.

Aquí está la respuesta json:

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

Seré muy apreciado por la ayuda para enfrentarlo.

UPD1: en este momento decidí hacerlo de la siguiente manera:

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 } } }


Puede crear una matriz que contenga las claves cuyos valores correspondientes sean nulos:

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

y luego recorra todos los elementos de esa matriz y elimine las claves del diccionario:

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


Suponiendo que solo desea filtrar los valores NSNull de un diccionario, esta es probablemente una de las mejores maneras de hacerlo. Está a prueba de futuro contra Swift 3, hasta donde sé por ahora:

(Gracias a AirspeedVelocity por la extensión, traducido a Swift 2)

import Foundation extension Dictionary { /// Constructs [key:value] from [(key, value)] init<S: SequenceType where S.Generator.Element == Element> (_ seq: S) { self.init() self.merge(seq) } mutating func merge<S: SequenceType where S.Generator.Element == Element> (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"]


Terminé con esto en 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 } } }

La misma respuesta, pero para 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<Key, Value> { 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) } } }


Solo tuve que resolver esto para un caso general en el que NSNulls podría anidarse en el diccionario en cualquier nivel, o incluso ser parte de una matriz:

extension Dictionary where Key == String, Value == Any { func strippingNulls() -> Dictionary<String, Any> { 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) } } } }

}

¡Espero que esto sea útil para otros y doy la bienvenida a las mejoras!

(Nota: esto es Swift 4)


Sugiriendo este enfoque, aplana valores opcionales y también es compatible con Swift 3

String Tecla de String , AnyObject? opcional AnyObject? diccionario de valor con valores nulos:

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

nil valores eliminados y transformados en diccionario de valor no opcional

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"]

La redeclaración var dict = dict es necesaria debido a la eliminación de los parámetros var en swift 3, por lo que para quick 2.1 podría ser;

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

Swift 4, sería;

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 }


La siguiente es la solución, cuando JSON tiene sub-dictionaries . Esto pasará por todos los dictionaries , sub-dictionaries de JSON y eliminará el par de key-value NULL (NSNull) del JSON .

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<Key, Value> } }