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

时间:2014-11-20 16:04:52

标签: ios json swift null nsdictionary

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

15 个答案:

答案 0 :(得分:10)

您可以创建一个包含相应值为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
}

答案 1 :(得分:9)

雨燕5

使用compactMapValues

dictionary.compactMapValues { $0 }

compactMapValues已在Swift 5中引入。有关更多信息,请参见Swift建议SE-0218

带有字典的示例

let json = [
    "FirstName": "Anvar",
    "LastName": "Azizov",
    "Website": nil,
    "About": nil,
]

let result = json.compactMapValues { $0 }
print(result) // ["FirstName": "Anvar", "LastName": "Azizov"]

包含JSON解析的示例

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.compactMapValues { $0 }
    print(result) // ["FirstName": "Anvar", "LastName": "Azizov"]
}

雨燕4

我可以通过将filtermapValues组合在一起来实现:

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

示例

使用上述示例,只需将let result替换为

let result = json.filter { $0.value != nil }.mapValues { $0! }

答案 2 :(得分:6)

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

Swift 4 让事情变得容易多了。只需直接使用词典filter

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

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

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

这会将NSNull值替换为nil,而不是删除密钥。

答案 3 :(得分:3)

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

(感谢AirspeedVelocity的扩展,转换为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"]

答案 4 :(得分:3)

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

带有nil值的

String键,可选AnyObject?值字典:

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
}

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

答案 5 :(得分:1)

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

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

你可以这样测试:

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

答案 6 :(得分:1)

雨燕5

  

compactMapValues(_:)

     

返回一个新字典,该字典仅包含具有   非nil值是给定闭包进行转换的结果。

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

let knownAges = people.compactMapValues { $0 }

答案 7 :(得分:1)

Swift5

使用 compactMapValues 创建字典扩展以备将来使用

extension Dictionary where Key == String, Value == Optional<Any> {
    func discardNil() -> [Key: Any] {
        return self.compactMapValues({ $0 })
    }
}

如何使用

public func toDictionary() -> [String: Any] {
    let emailAddress: String? = "test@mail.com"
    let phoneNumber: String? = "xxx-xxx-xxxxx"
    let newPassword: String = "**********"

    return [
        "emailAddress": emailAddress,
        "phoneNumber": phoneNumber,
        "passwordNew": newPassword
    ].discardNil()
}

答案 8 :(得分:0)

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

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

}

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

(注意:这是Swift 4)

答案 9 :(得分:0)

JSONsub-dictionaries时,以下是解决方案。 这将覆盖dictionaries的所有sub-dictionariesJSON,并从(NSNull)中移除NULL key-value 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>
    }
 }

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

Trim Null从NSDictionary获得崩溃的机会 将Dictionary传递给该函数并以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
}

答案 12 :(得分:0)

尝试用期望的值类型解开包装,并检查是否为nill或为空(如果是),然后从字典中删除该值。

如果字典中的值具有空值,这将起作用

答案 13 :(得分:0)

MySqlCommand

答案 14 :(得分:0)

如果您还没有使用 Swift 5,另一种快速的方法是...这将产生与 compactMapValues 相同的效果。

相同的字典,但没有可选项。

let cleanDictionary = originalDictionary.reduce(into: [String: Any]()) { $0[$1.key] = $1.value }

快速游乐场:

let originalDictionary = [
    "one": 1,
    "two": nil,
    "three": 3]

let cleanDictionary = originalDictionary.reduce(into: [String: Any]()) { $0[$1.key] = $1.value }    
for element in cleanDictionary {
    print(element)
}

输出:

<块引用>

[“一”:1,“三”:3]