根据 NSDictionary 键值将 NSArray 拆分为子数组
Posted
技术标签:
【中文标题】根据 NSDictionary 键值将 NSArray 拆分为子数组【英文标题】:Split NSArray into sub-arrays based on NSDictionary key values 【发布时间】:2013-01-15 10:16:19 【问题描述】:我们有一个应用程序调用 SOAP Web 服务并检索一长串 XML,然后应用程序将其解析为 NSArray
的 NSDictionary
对象。 NSArray
包含一个出租公寓信息列表,每个信息都存储在一个NSDictionary
中。
整个列表可能包含 10 种不同类型的公寓(即 2-room、3-room),我们需要根据 Room-Type 将 NSArray
拆分为更小的 NSArray
s,其中包含 key " NSDictionary
对象中的 roomType"。
目前我们的算法是
-
使用
[NSArray valueForKeyPath:@"@distinctUnionofObjects.room-type"]
获取唯一房间类型值的列表。
遍历唯一房间类型值列表
对于每个唯一的房间类型值,使用 NSPredicate
从原始列表中检索匹配项
我们的代码如下(为清楚起见重命名):
NSArray *arrOriginal = ... ...; // Contains the Parsed XML list
NSMutableArray *marrApartmentsByRoomType = [NSMutableArray arrayWithCapacity:10];
NSMutableArray *arrRoomTypes = [arrOriginal valueForKeyPath:@"distinctUnionOfObjects.roomType"];
for(NSString *strRoomType in arrRoomTypes)
NSPredicate *predicateRoomType = [NSPredicate predicateWithFormat:@"roomType=%@", strRoomType];
NSArray *arrApartmentsThatMatchRoomType = [arrOriginal filteredArrayUsingPredicate:predicateRoomType]; // TAKES A LONG TIME EACH LOOP-ROUND
[marrApartmentsByRoomType addObject:arrApartmentsThatMatchRoomType];
但是,第 3 步需要很长时间,因为原始列表可能包含大量 (>100,000) 项。 NSPredicate
似乎遍历了每个键值的整个列表。有没有更有效的方法可以根据 NSDictionary
键将大的 NSArray
拆分为较小的 NSArray
s?
【问题讨论】:
【参考方案1】:如果您的拆分数组的顺序不重要,我有一个解决方案:
NSArray *arrOriginal;
NSMutableDictionary *grouped = [[NSMutableDictionary alloc] initWithCapacity:arrOriginal.count];
for (NSDictionary *dict in arrOriginal)
id key = [dict valueForKey:@"roomType"];
NSMutableArray *tmp = [grouped objectForKey:key];
if (tmp == nil)
tmp = [[NSMutableArray alloc] init];
[grouped setObject:tmp forKey:key];
[tmp addObject:dict];
NSMutableArray *marrApartmentsByRoomType = [grouped allValues];
【讨论】:
感谢乔纳森的快速回复!将尝试使用它并测试性能是否更好。看来至少我们必须遍历整个原始数组一次......【参考方案2】:这是相当高效的
- (NSDictionary *)groupObjectsInArray:(NSArray *)array byKey:(id <NSCopying> (^)(id item))keyForItemBlock
NSMutableDictionary *groupedItems = [NSMutableDictionary new];
for (id item in array)
id <NSCopying> key = keyForItemBlock(item);
NSParameterAssert(key);
NSMutableArray *arrayForKey = groupedItems[key];
if (arrayForKey == nil)
arrayForKey = [NSMutableArray new];
groupedItems[key] = arrayForKey;
[arrayForKey addObject:item];
return groupedItems;
【讨论】:
【参考方案3】:改进@Jonathan 的回答
-
将数组转换为字典
保持与原始数组相同的顺序
//only to a take unique keys. (key order should be maintained)
NSMutableArray *aMutableArray = [[NSMutableArray alloc]init];
NSMutableDictionary *dictFromArray = [NSMutableDictionary dictionary];
for (NSDictionary *eachDict in arrOriginal)
//Collecting all unique key in order of initial array
NSString *eachKey = [eachDict objectForKey:@"roomType"];
if (![aMutableArray containsObject:eachKey])
[aMutableArray addObject:eachKey];
NSMutableArray *tmp = [grouped objectForKey:key];
tmp = [dictFromArray objectForKey:eachKey];
if (!tmp)
tmp = [NSMutableArray array];
[dictFromArray setObject:tmp forKey:eachKey];
[tmp addObject:eachDict];
//NSLog(@"dictFromArray %@",dictFromArray);
//NSLog(@"Unique Keys :: %@",aMutableArray);
//再次从字典转换为数组...
self.finalArray = [[NSMutableArray alloc]init];
for (NSString *uniqueKey in aMutableArray)
NSDictionary *aUniqueKeyDict = @@"groupKey":uniqueKey,@"featureValues":[dictFromArray objectForKey:uniqueKey];
[self.finalArray addObject:aUniqueKeyDict];
希望,当客户希望最终数组与输入数组的顺序相同时会有所帮助。
【讨论】:
以上是关于根据 NSDictionary 键值将 NSArray 拆分为子数组的主要内容,如果未能解决你的问题,请参考以下文章
php数组实现根据某个键值将相同键值合并生成新二维数组的方法