根据NSDictionary键值将NSArray拆分为子数组

4
我们有一个应用程序调用一个SOAP web服务并检索大量的XML,然后将其解析成一个NSDictionary对象的NSArray。该NSArray包含租赁公寓信息列表,每个公寓信息都存储在一个NSDictionary中。
整个列表可能包含10种不同类型的公寓(即2房、3房等),我们需要根据房间类型(在NSDictionary对象中具有"roomType"键)将NSArray分成更小的NSArray。
目前我们的算法是:
1.使用"[NSArray valueForKeyPath:@“distinctUnionofObjects.room-type”]"获取唯一的房间类型值列表。
2.循环遍历唯一的房间类型值列表。
3.对于每个唯一的房间类型值,使用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];
}

然而,第三步可能需要很长时间,因为原始列表可能包含大量(>100,000)的项目。似乎每个键值对都要通过整个列表的NSPredicate。是否有更有效的方法,可以根据NSDictionary键将大型NSArray分成较小的NSArray

3个回答

3
如果您分拆的数组的顺序不重要,那么我有一个解决方案:

如果您分拆的数组的顺序不重要,那么我有一个解决方案:

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];

谢谢你很快的回复,Jonathan!我会试一下,并测试一下使用它是否可以提高性能。似乎至少我们必须遍历整个原始数组一次... - AndyV

1
这非常高效。
- (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;
}

0

改进@Jonathan的答案

  1. 将数组转换为字典
  2. 保持与原始数组相同的顺序

    //仅取唯一键(键顺序应保持)
    NSMutableArray *aMutableArray = [[NSMutableArray alloc]init];
    
    NSMutableDictionary *dictFromArray = [NSMutableDictionary dictionary];
    
    for (NSDictionary *eachDict in arrOriginal) {
    //按照初始数组的顺序收集所有唯一键
    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];
    }
    
希望当客户希望最终数组与输入数组顺序相同时,这将有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接