webentwicklung-frage-antwort-db.com.de

Swift: Wie entferne ich einen Nullwert aus Dictionary?

Ich bin neu in Swift und habe ein Problem mit dem Filtern von NULL-Werten aus der JSON-Datei und deren Einstellung in Dictionary. Ich erhalte eine JSON-Antwort vom Server mit Nullwerten und meine App stürzt ab.

Hier ist die JSON-Antwort:

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

Ich bin sehr dankbar, wenn Sie mir helfen, damit umzugehen.

UPD1: In diesem Moment habe ich beschlossen, es auf folgende Weise zu tun:

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
      }
    }
}
13
Anvar Azizov

Sie können ein Array erstellen, das die Schlüssel enthält, deren Werte null sind:

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

und durchlaufen Sie als nächstes alle Elemente dieses Arrays und entfernen Sie die Schlüssel aus dem Wörterbuch:

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

Update 2017.01.17

Der Operator zum Entpacken der Kraft ist etwas hässlich, obwohl er sicher ist, wie in den Kommentaren erläutert. Es gibt wahrscheinlich mehrere andere Möglichkeiten, um dasselbe Ergebnis zu erzielen. Eine bessere Methode für dieselbe Methode ist:

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

Ich endete mit diesem in 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 }
    }
}

Gleiche Antwort, aber fü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<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) }
    }
}

In Swift 4 wird es viel einfacher. Verwenden Sie einfach die filter des Wörterbuchs direkt.

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

Wenn Sie die relevanten Schlüssel nicht entfernen möchten, können Sie Folgendes tun:

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

Dadurch werden die NSNull-Werte durch nil ersetzt, anstatt die Schlüssel zu entfernen.

6
Daniel T.

Schnell 4

Ich würde es tun, indem ich filter mit mapValues kombiniere:

dictionary.filter { $0.value != nil }.mapValues { $0! }

Beispiel mit Wörterbuch

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

Beispiel mit JSON-Analyse

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"]
}
6
Marián Černý

Durch diesen Ansatz werden optionale Werte abgeflacht und auch mit Swift 3 kompatibel

String key, optionales AnyObject?-Wertwörterbuch mit Nullwerten:

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

// ["first": {Some 1}, "second": {Some "2"}, "third": nil]

nullwerte entfernt und in ein nicht optionales Wertewörterbuch umgewandelt

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

Die Redeclaration var dict = dict wird benötigt, weil var-Parameter in Swift 3 entfernt wurden. Dies könnte für Swift 2.1 der Fall sein.

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

Swift 4 wäre;

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
}
3
Eralp Karaduman

Angenommen, Sie möchten nur NSNull-Werte aus einem Wörterbuch herausfiltern, ist dies wahrscheinlich eine der besseren Möglichkeiten, dies zu tun. Es ist zukunftssicher gegen Swift 3, soweit ich das vorläufig weiß:

(Dank an AirspeedVelocity für die Erweiterung, übersetzt nach 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"]
3
ColGraff

Swift 5

compactMapValues ​​(_:)

Gibt ein neues Wörterbuch zurück, das nur die Schlüssel-Wert-Paare enthält, die als Ergebnis der Transformation durch den angegebenen Abschluss Nicht-Null-Werte haben.

let people = [
    "Paul": 38,
    "Sophie": 8,
    "Charlotte": 5,
    "William": nil
]

let knownAges = people.compactMapValues { $0 }
1
Saranjith

Da Swift 4 die Methode reduce(into:_:) für die Klasse Dictionary bereitstellt, können Sie mit der folgenden Funktion nil-values ​​aus Dictionary entfernen:

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

Sie können es so testen:

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

Versuchen Sie, es mit dem erwarteten Wertetyp zu entpacken, und prüfen Sie, ob der Wert null oder leer ist. Wenn ja, entfernen Sie diesen Wert aus dem Wörterbuch.

Dies funktioniert, wenn die Werte im Wörterbuch leere Werte haben

0
Teja Swaroop

Ich musste dies nur für einen allgemeinen Fall lösen, in dem NSNulls auf jeder Ebene im Wörterbuch verschachtelt werden konnte oder sogar Teil eines Arrays sein konnte:

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

}

Ich hoffe das hilft anderen und Ich freue mich über Verbesserungen!

(Hinweis: das ist Swift 4)

0
buildsucceeded

Im Folgenden finden Sie die Lösung, wenn JSON über sub-dictionaries. Verfügt. Dadurch werden alle dictionaries, sub-dictionaries von JSON durchlaufen und das Paar NULL(NSNull)key-value aus der JSON entfernt.

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

Trimmen Sie das Null-Form-NSDictionary ab, um die Funktion des Absturzes abzurufen Übergeben Sie das Dictionary an diese Funktion, und erhalten Sie das Ergebnis als 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
}
0
Sandeep Kalia

Sie können die Nullwerte durch folgende Funktion in leere Zeichenfolge ersetzen.

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;
}
0
Anita