比较两个 NSArray 并检测变化的最佳方法是什么
What is the best way to compare two NSArrays and detect changes
我的要求是确定地址簿中的更改(自上次打开应用程序以来更改了哪些联系人和哪些字段。
现在我有两个 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";
}
);
},
arr联系人
{
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 被更改。
由于地址簿中可以有数千个项目,我的问题是,比较这两个数组并检测更改的项目(删除、添加、内部字段的更改)的最佳和最佳方法是什么?
非常感谢代码示例
继续 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];
这是检查更改、添加和删除的代码。请查收,如有不明白请评论...
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]];
怎么样……
// 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];
每个数组枚举一次。
我的要求是确定地址簿中的更改(自上次打开应用程序以来更改了哪些联系人和哪些字段。
现在我有两个 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";
}
);
},
arr联系人
{
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 被更改。
由于地址簿中可以有数千个项目,我的问题是,比较这两个数组并检测更改的项目(删除、添加、内部字段的更改)的最佳和最佳方法是什么?
非常感谢代码示例
继续 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];
这是检查更改、添加和删除的代码。请查收,如有不明白请评论...
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]];
怎么样……
// 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];
每个数组枚举一次。