Je suis nouveau dans Swift et j'ai un problème avec le filtrage des valeurs NULL à partir d'un fichier JSON et sa définition dans Dictionary. Je reçois une réponse JSON du serveur avec des valeurs null et mon application se bloque.
Voici la réponse JSON:
"FirstName": "Anvar",
"LastName": "Azizov",
"Website": null,
"About": null,
Je serai très apprécié de l'aide pour y faire face.
UPD1: À ce moment, j'ai décidé de le faire d'une autre manière:
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
}
}
}
Vous pouvez créer un tableau contenant les clés dont les valeurs correspondantes sont nil:
let keysToRemove = dict.keys.array.filter { dict[$0]! == nil }
et ensuite, parcourez tous les éléments de ce tableau et supprimez les clés du dictionnaire:
for key in keysToRemove {
dict.removeValueForKey(key)
}
Mise à jour 2017.01.17
L'opérateur de déploiement de la force est un peu moche, bien que sûr, comme expliqué dans les commentaires. Il existe probablement plusieurs autres moyens d'obtenir le même résultat. Une méthode plus esthétique de la même méthode est la suivante:
let keysToRemove = dict.keys.filter {
guard let value = dict[$0] else { return false }
return value == nil
}
J'ai fini avec ceci dans 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 }
}
}
Même réponse mais pour 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) }
}
}
Les choses deviennent beaucoup plus faciles dans Swift 4 . Il suffit d'utiliser la variable filter
du dictionnaire directement.
jsonResult.filter { !($0.1 is NSNull) }
Ou si vous ne souhaitez pas supprimer les clés pertinentes, vous pouvez procéder comme suit:
jsonResult.mapValues { $0 is NSNull ? nil : $0 }
Ce qui remplacera les valeurs NSNull
par nil
au lieu de supprimer les clés.
Je le ferais en combinant filter
avec mapValues
:
dictionary.filter { $0.value != nil }.mapValues { $0! }
let json = [
"FirstName": "Anvar",
"LastName": "Azizov",
"Website": nil,
"About": nil,
]
let result = json.filter { $0.value != nil }.mapValues { $0! }
print(result) // ["FirstName": "Anvar", "LastName": "Azizov"]
let jsonText = """
{
"FirstName": "Anvar",
"LastName": "Azizov",
"Website": null,
"About": null
}
"""
let data = jsonText.data(using: .utf8)!
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let json = json as? [String: Any?] {
let result = json.filter { $0.value != nil }.mapValues { $0! }
print(result) // ["FirstName": "Anvar", "LastName": "Azizov"]
}
Suggérant cette approche, aplatit les valeurs optionnelles et est également compatible avec Swift 3.
Clé String
, dictionnaire de valeurs AnyObject?
facultatif avec des valeurs nulles:
let nullableValueDict: [String : AnyObject?] = [
"first": 1,
"second": "2",
"third": nil
]
// ["first": {Some 1}, "second": {Some "2"}, "third": nil]
valeurs nulles supprimées et transformées en dictionnaire de valeurs non optionnelles
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 redéclaration var dict = dict
est nécessaire en raison de la suppression des paramètres var dans Swift 3, ce qui est le cas pour 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
}
Swift 4, serait;
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
}
En supposant que vous souhaitiez simplement filtrer les valeurs NSNull
d'un dictionnaire, c'est probablement l'une des meilleures façons de procéder. Il est à l’avenir contre Swift 3, pour autant que je sache pour le moment:
(Merci à AirspeedVelocity pour l'extension, traduit en 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"]
Puisque Swift 4 fournit la méthode reduce(into:_:)
pour la classe Dictionary
, vous pouvez supprimer les valeurs nil de Dictionary
avec la fonction suivante:
func removeNilValues<K,V>(dict:Dictionary<K,V?>) -> Dictionary<K,V> {
return dict.reduce(into: Dictionary<K,V>()) { (currentResult, currentKV) in
if let val = currentKV.value {
currentResult.updateValue(val, forKey: currentKV.key)
}
}
}
Vous pouvez le tester comme ça:
let testingDict = removeNilValues(dict: ["1":nil, "2":"b", "3":nil, "4":nil, "5":"e"])
print("test result is \(testingDict)")
Je devais simplement résoudre ce problème dans un cas général où NSNulls pouvait être imbriqué dans le dictionnaire à n'importe quel niveau, ou même faire partie d'un tableau:
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)
}
}
}
}
}
J'espère que cela aidera les autres et j'apprécie les améliorations!
(Note: c'est Swift 4)
Voici la solution: lorsque JSON
a sub-dictionaries
. Cela va parcourir toutes les dictionaries
, sub-dictionaries
de JSON
et supprimer NULL(NSNull)
key-value
paire de la 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>
}
}
Supprimez la forme Null de NSDictionary pour éviter les accidents Transférer un dictionnaire pour cette fonction et obtenir le résultat sous NSMutableDictionary
func trimNullFromDictionaryResponse(dic:NSDictionary) -> NSMutableDictionary {
let allKeys = dic.allKeys
let dicTrimNull = NSMutableDictionary()
for i in 0...allKeys.count - 1 {
let keyValue = dic[allKeys[i]]
if keyValue is NSNull {
dicTrimNull.setValue("", forKey: allKeys[i] as! String)
}
else {
dicTrimNull.setValue(keyValue, forKey: allKeys[i] as! String)
}
}
return dicTrimNull
}
Vous pouvez remplacer les valeurs NULL par une chaîne vide en suivant la fonction.
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;
}