[英]Swift: How to remove a null value from Dictionary?
我是 Swift 的新手,我在从 JSON 文件中过滤 NULL 值并将其设置到字典中时遇到了问题。 我从服务器收到带有空值的 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
}
}
}
使用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"]
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"]
}
我会通过将filter
与mapValues
结合来做到这mapValues
:
dictionary.filter { $0.value != nil }.mapValues { $0! }
使用上面的示例只需将let result
替换为
let result = json.filter { $0.value != nil }.mapValues { $0! }
您可以创建一个包含对应值为 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<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 中事情变得容易多了。 直接使用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<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"]
建议采用这种方法,将可选值展平并与 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
}
紧凑地图值(_:)
返回一个新字典,该字典仅包含作为给定闭包转换结果的非 nil 值的键值对。
let people = [
"Paul": 38,
"Sophie": 8,
"Charlotte": 5,
"William": nil
]
let knownAges = people.compactMapValues { $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;
}
由于 Swift 4 为类Dictionary
提供了reduce(into:_:)
,因此您可以使用以下函数从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)")
斯威夫特5
使用 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()
}
我只需要在一般情况下解决这个问题,其中 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)
以下是解决方案,当JSON
有sub-dictionaries
。 这将大大-通过所有的dictionaries
, sub-dictionaries
的JSON
和删除NULL (NSNull)
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>
}
}
修剪 Null 形式 NSDictionary 以摆脱崩溃传递字典到此函数并获得结果作为 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
}
尝试使用预期类型的值打开它并检查是否为 nill 或为空(如果是),然后从字典中删除该值。
如果字典中的值有空值,这将起作用
//
// Collection+SF.swift
// PanoAI
//
// Created by Forever Positive on 2021/1/30.
//
import Foundation
extension Array where Element == Optional<Any>{
var trimed:[Any] {
var newArray = [Any]()
for item in self{
if let item = item as? [Any?] {
newArray.append(contentsOf: item.trimed)
}else if item is NSNull || item == nil {
//skip
}else if let item = item{
newArray.append(item)
}
}
return newArray
}
}
extension Dictionary where Key == String, Value == Optional<Any> {
var trimed:[Key: Any] {
return self.compactMapValues({ v in
if let dic = v as? [String:Any?] {
return dic.trimed
}else if let _ = v as? NSNull {
return nil;
}else if let array = v as? [Any?] {
return array.trimed;
}else{
return v;
}
})
}
}
// MARK: - Usage
//let dic:[String:Any?] = ["a":"a","b":nil,"c":NSNull(),"d":["1":"1","2":nil,"3":NSNull(),"4":["a","b",nil,NSNull()]],"e":["a","b",nil,NSNull()]]
//print(dic.trimed)
如果您还没有使用 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]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.