比较两个 NSArray 并检测更改的最佳方法是啥

Posted

技术标签:

【中文标题】比较两个 NSArray 并检测更改的最佳方法是啥【英文标题】:What is the best way to compare two NSArrays and detect changes比较两个 NSArray 并检测更改的最佳方法是什么 【发布时间】:2015-09-19 03:46:44 【问题描述】:

我的要求是确定地址簿中的更改(自上次打开应用程序以来,哪些联系人和哪些字段发生了更改。

现在我有两个 NSArrays 作为 arrSavedContacts(包含以前的通讯录联系人)和 arrContacts(当前通讯录联系人)。这就是两个数组的样子

arrSavedContacts


    firstName = Gayan;
    id = 224;
    lastName = Udaha;
    phones =         (
                    
            label = Mobile;
            value = "123456789";
        
    );
,
    
    firstName = Chandrananda;
    id = 225;
    lastName = "";
    phones =         (
                    
            label = Mobile;
            value = "234567891";
        
    );
,
    
    firstName = Joe;
    id = 228;
    lastName = B8;
    phones =         (
                    
            label = Mobile;
            value = "345678912";
        
    );
,

arrContacts


    firstName = FirstName Changed;
    id = 224;
    lastName = Udaha;
    phones =         (
                    
            label = Mobile;
            value = "123456789";
        
    );
,
    
    firstName = Chandrananda;
    id = 225;
    lastName = "";
    phones =         (
                    
            label = Mobile;
            value = "345678912";
        
    );
,

作为上面的两个数组,我们可以注意到两个变化,第 3 项被删除,第 1 项中的 firstName 被改变。

由于地址簿中可以有数千个项目,我的问题是,比较这两个数组并检测更改的项目(删除、添加、内部字段的更改)的最佳和最佳方法是什么?

非常感谢一个代码示例

【问题讨论】:

你的数据结构几乎不可能做你想做的事。你真的需要一个字典而不是字典数组。外部字典应该为每个联系人条目键入某种唯一的 id。然后您可以通过键关联两个(保存和更改的)字典。然后你可以比较每个对应的内部字典来寻找变化。 @rmaddy 感谢您的想法,如果您能展示一些示例,我们将不胜感激 arrSavedContacts 开头。你有一个字典数组。相反,将所有字典放在字典而不是数组中。您现有的字典将是字典中的值,每个联系人的某种唯一 ID 将是其键。现在对arrContacts 执行相同的操作。现在每个联系人将在两组数据中具有相同的唯一 ID。 【参考方案1】:

这是检查更改、添加和删除的代码。请检查一下,如果不明白请评论...

NSMutableArray *oldArr =[NSMutableArray arrayWithArray:@[@
                                                             @"firstName" : @"Gayan",
                                                             @"id" : @224,
                                                             @"lastName" : @"Udaha",
                                                             @"phones": @[
                                                                     @
                                                                         @"label" : @"Mobile",
                                                                         @"value" : @"123456789"
                                                                      
                                                                     ]
                                                             ,
                                                         @
                                                             @"firstName" : @"Chandrananda",
                                                             @"id" : @225,
                                                             @"lastName" : @"",
                                                             @"phones": @[
                                                                     @
                                                                         @"label" : @"Mobile",
                                                                         @"value" : @"234567891"
                                                                         
                                                                     ]
                                                             ,
                                                         @
                                                             @"firstName" : @"Joe",
                                                             @"id" : @226,
                                                             @"lastName" : @"",
                                                             @"phones": @[
                                                                     @
                                                                         @"label" : @"Mobile",
                                                                         @"value" : @"345678912"
                                                                         
                                                                     ]
                                                             ,
]];

NSMutableArray *newArr =[NSMutableArray arrayWithArray:@[@
                                                             @"firstName" : @"Gayan",
                                                             @"id" : @224,
                                                             @"lastName" : @"Udaha",
                                                             @"phones": @[
                                                                     @
                                                                         @"label" : @"Mobile",
                                                                         @"value" : @"123456789"
                                                                         
                                                                     ]
                                                             ,
                                                         @
                                                             @"firstName" : @"Chandrananda",
                                                             @"id" : @225,
                                                             @"lastName" : @"",
                                                             @"phones": @[
                                                                     @
                                                                         @"label" : @"Mobile",
                                                                         @"value" : @"11111111"
                                                                         
                                                                     ]
                                                             ,
                                                         @
                                                             @"firstName" : @"Luan",
                                                             @"id" : @229,
                                                             @"lastName" : @"",
                                                             @"phones": @[
                                                                     @
                                                                         @"label" : @"Mobile",
                                                                         @"value" : @"55555555"
                                                                         
                                                                     ]
                                                             ,
                                                         ]];


NSMutableSet *oldSet = [NSMutableSet setWithArray:oldArr];
NSMutableSet *newSet = [NSMutableSet setWithArray:newArr];

//1: Get filter all changed, add, delete items

[oldSet minusSet:newSet];
[newSet minusSet:oldSet];

NSArray *remainOldArr = [NSArray arrayWithArray:[oldSet allObjects]];
NSArray *remainNewArr = [NSArray arrayWithArray:[newSet allObjects]];

if (remainNewArr.count == 0 && remainOldArr.count == 0) 
    // there is no changes.
    return ;


//2: detect which items changed,add,delete

NSMutableArray *arrayChangedItems = nil;
NSMutableArray *arrayDeleteItems = nil;
NSMutableArray *arrayAddItems =nil;

NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"self.id IN %@",[remainOldArr valueForKeyPath:@"id"]];
NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"NOT self.id IN %@",[remainOldArr valueForKeyPath:@"id"]];
NSPredicate *pre3 = [NSPredicate predicateWithFormat:@"NOT self.id IN %@",[remainNewArr valueForKeyPath:@"id"]];

arrayChangedItems = [NSMutableArray arrayWithArray:[remainNewArr filteredArrayUsingPredicate:pre1]];
arrayAddItems = [NSMutableArray arrayWithArray:[remainNewArr filteredArrayUsingPredicate:pre2]];
arrayDeleteItems = [NSMutableArray arrayWithArray:[remainOldArr filteredArrayUsingPredicate:pre3]];

【讨论】:

我测试了代码,但每次它都为arrayAddItems和arrayDeleteItems返回空数组。 arrayChangedItems 始终是完整的项目集 超酷的答案。在我的情况下,它需要像这样稍微改变谓词。 pre2 和 pre3 在进行减集操作之前应该使用数组。此外,filteredArrayUsingPredicate 操作应该使用相同的数组【参考方案2】:

延续 rmaddy 的建议,将数据放在字典的字典中以便首先根据唯一 ID 轻松查找删除是有意义的。例如,你的基本字典应该是这样的:

 224 = 
        firstName = Gayan;
        id = 224;
        lastName = Udaha;
        phones = (
               
                 label = Mobile;
                 value = "123456789";
               
                );
        

    225 = 
        firstName = Chandrananda;
        id = 225;
        lastName = "";
        phones =  (
               
                 label = Mobile;
                 value = "234567891";
                
                 );
    

现在,一旦您的数据设置正确,您就可以在NSDictionary上添加一个类别并实现以下方法:

- (NSArray*)changedKeysIn:(NSDictionary*)iAnotherDict 
    NSMutableArray *changedKeys = [NSMutableArray array];

    for (id key in self) 
        if(![[self objectForKey:key] isEqual:[iAnotherDict objectForKey:key]])
            [changedKeys addObject:key];
        

        return changedKeys;

然后简单地这样称呼它:

[baseDict changedKeysIn:anotherDict];

【讨论】:

这是一个开始。这仅适用于在两个字典中找到的键。逻辑需要添加从一个或另一个字典中添加或删除的键。并且需要添加逻辑以查看更改后的联系人字典中发生了什么变化。 @rmaddy 是的,我设法将数据集作为字典获取,每个内部字典都有一个 uniq 键。第224章姓氏 = 乌达哈;手机=(标签=手机;值=“1234567890”;); ;但仍然无法弄清楚检测内部字段变化的逻辑 @sajaz 一旦你知道两个对应的字典是不同的,你将不得不一次比较每个字段。没有捷径。【参考方案3】:

怎么样……

// put new contacts in a dictionary
NSMutableDictionary *aDictionary = [NSMutableDictionary dictionary];
[arrContacts enumerateObjectsUsingBlock:^(id theNewContact, NSUInteger idx, BOOL *stop)

    [aDictionary setObject:theNewContact forKey:[theNewContact valueForKey:@"id"]];
];

// check each old contact
[arrSavedContacts enumerateObjectsUsingBlock:^(id theOldContact, NSUInteger idx, BOOL *stop)

    NSDictionary *aNewContact = [aDictionary objectForKey:[theOldContact valueForKey:@"id"]];
    if (aNewContact == nil)
    
        // delete old contact
    
    else
    
        if (![aNewContact isEqual:theOldContact])
        
            // update old contact
        
        // remove existing contact from the dictionary
        [aDictionary removeObjectForKey:[theOldContact valueForKey:@"id"]];
    
];

// new contacts
[aDictionary allValues];

每个数组被枚举一次。

【讨论】:

以上是关于比较两个 NSArray 并检测更改的最佳方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

比较两个 CultureInfo 实例的最佳方法是啥?

比较具有相同数据但标记不同的两个 HTML 页面的最佳方法是啥

在 c# 中比较两个 pdf 文件的最佳方法是啥?

在 C/C++ 项目中自动检测库依赖关系的最佳方法是啥?

生成 Android 房间迁移的最佳方法是啥?

在一个 GPU 上加载 TRT 引擎以进行两次推理的最佳方法是啥?