如何从 NSDictionary 中删除空值

Posted

技术标签:

【中文标题】如何从 NSDictionary 中删除空值【英文标题】:How to remove a null value from NSDictionary 【发布时间】:2012-12-18 08:44:34 【问题描述】:

我有一个 JSON 提要:


    "count1" = 2;
    "count2" = 2;
    idval = 40;
    level = "<null>";
    "logo_url" = "/assets/logos/default_logo_medium.png";
    name = "Golf Club";
    "role_in_club" = Admin;

问题是"&lt;null&gt;"。在将其保存到 NSUserDefaults 之前,我无法弄清楚如何将其从 NSDictionary 中删除。

【问题讨论】:

因为您可以将空值保存到 NSUserDefaults。 啊,“在将它们保存到 NSUserDefaults 之前” - 抱歉,还没有阅读。 ***.com/a/40343081/2273338 【参考方案1】:

遍历字典并查找任何空条目并将其删除。

NSMutableDictionary *prunedDictionary = [NSMutableDictionary dictionary];
for (NSString * key in [yourDictionary allKeys])

    if (![[yourDictionary objectForKey:key] isKindOfClass:[NSNull class]])
        [prunedDictionary setObject:[yourDictionary objectForKey:key] forKey:key];

之后,prunedDictionary 应该在原始字典中包含所有非空项。

【讨论】:

我想知道哪个性能更好:创建字典的可变副本,然后从中删除对象或手动将所有值添加到字典中...... @RichardJ.RossIII 除非数组 非常 大,否则真的没关系。如果数组 足够大,我会尝试两种方式,看看哪个最快。【参考方案2】:

要删除它,请将其转换为可变字典并删除键“级别”的对象;

NSDictionary* dict = ....;  // this is the dictionary to modify
NSMutableDictionary* mutableDict = [dict mutableCopy];
[mutableDict removeObjectForKey:@"level"];
dict = [mutableDict copy];

如果您不使用 ARC,则需要添加一些对“释放”的调用。

更新:

如果您不知道 "&lt;null&gt;" 对象的键名,那么您必须进行迭代:

NSDictionary* dict = ....;  // this is the dictionary to modify
NSMutableDictionary* mutableDict = [dict mutableCopy];
for (id key in dict) 
    id value = [dict objectForKey: key];
    if ([@"<null>" isEqual: value]) 
        [mutableDict removeObjectForKey:key];
    

dict = [mutableDict copy];

为了定位"&lt;null&gt;" 值,我使用了字符串比较,因为"&lt;null&gt;" 是您示例中的字符串。但我不确定是否真的如此。

【讨论】:

事实并非如此。如果它是一个不会有问题的字符串。这里的问题是解析将产生一个NSNull 实例读取“”并且该值不能存储在NSUserDefaults 中。 我有点困惑。问题中的示例不是 JSON,但很可能是字典的 NSLog 输出(在解析 JSON 数据之后)。如果键 level 的值是 NSNull 实例,它会打印 &lt;null&gt; 而不是 "&lt;null&gt;"。所以要么值是字符串,要么样本错误。 加布里埃拉你是对的。问题是它正在获取一个存储为“”的值并且它无法识别它。通常它会给我一个像 null 这样的值。【参考方案3】:

另一种变体,没有(显式)循环:

NSMutableDictionary *dict = [yourDictionary mutableCopy];
NSArray *keysForNullValues = [dict allKeysForObject:[NSNull null]];
[dict removeObjectsForKeys:keysForNullValues];

【讨论】:

同样,您可以通过将 [NSNull null] 替换为 @"" 来删除所有空条目 这是一个很酷的代码,但是如果我们将字典放入数组中,我们可以做什么。【参考方案4】:

使用它从字典中删除 null

- (NSMutableDictionary *)recursive:(NSMutableDictionary *)dictionary 
for (NSString *key in [dictionary allKeys])     
    id nullString = [dictionary objectForKey:key];   
    if ([nullString isKindOfClass:[NSDictionary class]]) 
        [self recursive:(NSMutableDictionary*)nullString];
     else 
        if ((NSString*)nullString == (id)[NSNull null])
            [dictionary setValue:@"" forKey:key];
    

return dictionary;

【讨论】:

用@"" 替换空值,这可能是也可能不是你想要的:-) “[字典 setValue:@"" forKey:key];”这可能会崩溃。子/递归字典可能不是 mutableDictionary。所以我们可以使用一个新的 mutableDictionary 来收集每个非空值和子字典值。【参考方案5】:

我相信这是最节省资源的方式

// NSDictionary 上的类别实现

- (NSDictionary *)dictionaryByRemovingNullValues 

    NSMutableDictionary * d;
    for (NSString * key in self) 

        if (self[key] == [NSNull null]) 
            if (d == nil) 
                d = [NSMutableDictionary dictionaryWithDictionary:self];
            
            [d removeObjectForKey:key];
        

    

    if (d == nil) 
        return self;
    

    return d;

【讨论】:

【参考方案6】:

我已经为 NSJSOn 序列化类创建了一个类别。

创建一个类别并导入类以使用其方法...

// Mutable containers are required to remove nulls.
if (replacingNulls)

    // Force add NSJSONReadingMutableContainers since the null removal depends on it.
    opt = opt || NSJSONReadingMutableContainers;


id JSONObject = [self JSONObjectWithData:data options:opt error:error];

if ((error && *error) || !replacingNulls)

    return JSONObject;


[JSONObject recursivelyReplaceNullsIgnoringArrays:ignoreArrays withString:replaceString];
return JSONObject;

【讨论】:

【参考方案7】:

这是我的基于类别的递归解决方案,用于包含字典和数组的字典,其中值也可以是字典和数组:

文件NSDictionary+Dario.m

#import "NSArray+Dario.h"

@implementation NSDictionary (Dario)

- (NSDictionary *) dictionaryByReplacingNullsWithEmptyStrings 

    const NSMutableDictionary *replaced = [NSMutableDictionary new];
    const id nul = [NSNull null];
    const NSString *blank = @"";

    for(NSString *key in self) 
        const id object = [self objectForKey:key];
        if(object == nul) 
            [replaced setObject:blank forKey:key];
         else if ([object isKindOfClass:[NSDictionary class]]) 
            [replaced setObject:[object dictionaryByReplacingNullsWithEmptyStrings] forKey:key];
         else if ([object isKindOfClass:[NSArray class]]) 
            [replaced setObject:[object arrayByReplacingNullsWithEmptyStrings] forKey:key];
         else 
            [replaced setObject:object forKey:key];
        
    
    return [NSDictionary dictionaryWithDictionary:(NSDictionary*)replaced];


@end

文件NSArray+Dario.m

#import "NSDictionary+Dario.h"

@implementation NSArray (Dario)

- (NSArray *) arrayByReplacingNullsWithEmptyStrings 
    const NSMutableArray *replaced = [NSMutableArray new];
    const id nul = [NSNull null];
    const NSString *blank = @"";

    for (int i=0; i<[self count]; i++) 
        const id object = [self objectAtIndex:i];

        if ([object isKindOfClass:[NSDictionary class]]) 
            [replaced setObject:[object dictionaryByReplacingNullsWithEmptyStrings] atIndexedSubscript:i];
         else if ([object isKindOfClass:[NSArray class]]) 
            [replaced setObject:[object arrayByReplacingNullsWithEmptyStrings] atIndexedSubscript:i];
         else if (object == nul)
            [replaced setObject:blank atIndexedSubscript:i];
         else 
            [replaced setObject:object atIndexedSubscript:i];
        
    
    return [NSArray arrayWithArray:(NSArray*)replaced];

【讨论】:

【参考方案8】:

我尝试了你的问题的解决方案,我明白了

NSDictionary *dict = [[NSDictionary alloc]initWithObjectsAndKeys:@"2",@"count1",@"2",@"count2",@"40",@"idval",@"<null>",@"level",@"/assets/logos/default_logo_medium.png",@"logo_url",@"Golf Club",@"name",@"role_in_club",@"Admin", nil];
NSMutableDictionary *mutableDict = [dict mutableCopy];
for (NSString *key in [dict allKeys]) 
    if ([dict[key] isEqual:[NSNull null]]) 
        mutableDict[key] = @""; 
    
    if([dict[key] isEqualToString:@"<null>"])
    
        mutableDict[key] = @"";
    

dict = [mutableDict copy];
NSLog(@"The dict is - %@",dict);

最终答案是

The dict is - 
Admin = "role_in_club";
count1 = 2;
count2 = 2;
idval = 40;
level = "";
"logo_url" = "/assets/logos/default_logo_medium.png";
name = "Golf Club";

【讨论】:

我试过了,然后我才用结果发布了我的答案。它有效。【参考方案9】:

我就是这样做的。

NSMutableDictionary *prunedDict = [NSMutableDictionary dictionary];
[self enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) 
  if (![obj isKindOfClass:[NSNull class]]) 
    prunedDict[key] = obj;
  
];

【讨论】:

【参考方案10】:

以下代码在结果为数组或字典的情况下是可以的,你可以通过编辑代码将返回的结果更改为nil或空字符串

函数是递归的,所以可以解析字典中的数组。

-(id)changeNull:(id)sender
    
    id newObj;
    
    if ([sender isKindOfClass:[NSArray class]])

        NSMutableArray *newArray = [[NSMutableArray alloc] init];
        
        
        for (id item in sender)
        
            [newArray addObject:[self changeNull:item]];
        
        
        
        newObj = newArray;
    
    
    else if ([sender isKindOfClass:[NSDictionary class]])
        
        NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
        
        for (NSString *key in sender)
            
            NSDictionary *oldDict = (NSDictionary*)sender;
            
            
            id item = oldDict[key];

            if (![item isKindOfClass:[NSDictionary class]] && ![item isKindOfClass:[NSArray class]])

                if ([item isEqual:[NSNull null]])
                    item = @"";
                    
                
                
                [newDict setValue:item forKey:key];

            
            else
                
                [newDict setValue:[self changeNull:item] forKey:key];
                
            
        
        newObj = newDict;
    
    
    return newObj;

导致:

jsonresult (
    
        Description = "<null>";
        Id = 1;
        Name = High;
    ,
        
        Description = "<null>";
        Id = 2;
        Name = Medium;
    ,
        
        Description = "<null>";
        Id = 3;
        Name = Low;
    
)

change null (
    
        Description = "";
        Id = 1;
        Name = High;
    ,
        
        Description = "";
        Id = 2;
        Name = Medium;
    ,
        
        Description = "";
        Id = 3;
        Name = Low;
    
)

【讨论】:

【参考方案11】:

Swift 3.0/4.0解决方案

以下是解决方案,当JSON 拥有sub-dictionaries。这将遍历所有dictionariesJSON 的子-dictionaries 并从JSON 中删除NULL(NSNull) key-value 对。

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>
    
 

【讨论】:

谢谢,我已经更新了我的答案。实际上嵌入链接的答案也是我发布的。【参考方案12】:

在你的视图控制器中添加这3个方法,并像这样调用这个方法

NSDictionary *dictSLoginData = [self removeNull:[result valueForKey:@"data"]];

- (NSDictionary*)removeNull:(NSDictionary *)dict 

    NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary: dict];

    const id nul = [NSNull null];
    const NSString *blank = @"";

    for (NSString *key in [dict allKeys]) 

        const id object = [dict objectForKey: key];
        if (object == nul) 
            [replaced setObject: blank forKey: key];
         else if([object isKindOfClass: [NSDictionary class]]) 
            [replaced setObject: [self replaceNull:object] forKey: key];
         else if([object isKindOfClass: [NSArray class]]) 
            [replaced setObject: [self replaceNullArray:object] forKey: key];
        
    
    return [NSDictionary dictionaryWithDictionary: replaced];


- (NSArray *)replaceNullArray:(NSArray *)array 

    const id nul = [NSNull null];
    const NSString *blank = @"";

    NSMutableArray *replaced = [NSMutableArray arrayWithArray:array];

    for (int i=0; i < [array count]; i++) 
        const id object = [array objectAtIndex:i];
        if (object == nul) 
            [replaced replaceObjectAtIndex:i withObject:blank];
         else if([object isKindOfClass: [NSDictionary class]]) 
            [replaced replaceObjectAtIndex:i withObject:[self replaceNull:object]];
         else if([object isKindOfClass: [NSArray class]]) 
            [replaced replaceObjectAtIndex:i withObject:[self replaceNullArray:object]];
        
    
    return replaced;


- (NSDictionary *)replaceNull:(NSDictionary *)dict 

    const id nul = [NSNull null];
    const NSString *blank = @"";

    NSMutableDictionary *replaced = [NSMutableDictionary dictionaryWithDictionary: dict];

    for (NSString *key in [dict allKeys]) 
        const id object = [dict objectForKey: key];
        if (object == nul) 
            [replaced setObject: blank forKey: key];
         else if ([object isKindOfClass: [NSDictionary class]]) 
            [replaced setObject: [self replaceNull:object] forKey: key];
         else if([object isKindOfClass: [NSArray class]]) 
            [replaced setObject: [self replaceNullArray:object] forKey: key];
        
    
    return replaced;

【讨论】:

【参考方案13】:

修改@sinh99 答案。使用新的 NSMutableDictionary 来收集非空值和子字典值。


- (NSMutableDictionary *)recursiveRemoveNullValues:(NSDictionary *)dictionary 

    NSMutableDictionary *mDictionary = [NSMutableDictionary new];
    for (NSString *key in [dictionary allKeys]) 
        id nullString = [dictionary objectForKey:key];

        if ([nullString isKindOfClass:[NSDictionary class]]) 
            NSMutableDictionary *mDictionary_sub = [self recursiveRemoveNullValues:(NSDictionary*)nullString];
            [mDictionary setObject:mDictionary_sub forKey:key];
         else 

            if ((NSString*)nullString == (id)[NSNull null]) 
                [mDictionary setValue:@"" forKey:key];
             else 
                [mDictionary setValue:nullString forKey:key];
            
        
    

    return mDictionary;



【讨论】:

【参考方案14】:

Swift - 支持嵌套 NSNull

首先,我们在 Swift 中使用Dictionary 而不是NSDictionary

要删除任何嵌套级别(包括数组字典)中的任何 NSNull外观,请尝试以下操作:

extension Dictionary where Key == String 
    func removeNullsFromDictionary() -> Self 
        var destination = Self()
        for key in self.keys 
            guard !(self[key] is NSNull) else  destination[key] = nil; continue 
            guard !(self[key] is Self) else  destination[key] = (self[key] as! Self).removeNullsFromDictionary() as? Value; continue 
            guard self[key] is [Value] else  destination[key] = self[key]; continue 

            let orgArray = self[key] as! [Value]
            var destArray: [Value] = []
            for item in orgArray 
                guard let this = item as? Self else  destArray.append(item); continue 
                destArray.append(this.removeNullsFromDictionary() as! Value)
            
            destination[key] = destArray as? Value
        
        return destination
    

注意字典的key应该是String

【讨论】:

以上是关于如何从 NSDictionary 中删除空值的主要内容,如果未能解决你的问题,请参考以下文章

NSDictionary 具有空值

复制没有空值的 NSDictionary?

如何从 NSDictionary 中删除对象

如何从数组中删除空值? [复制]

如何从json输入中删除空值

我将如何从每列中删除空值