【问题标题】:Split NSArray into sub-arrays based on NSDictionary key values根据 NSDictionary 键值将 NSArray 拆分为子数组
【发布时间】:2013-01-15 10:16:19
【问题描述】:

我们有一个应用程序调用 SOAP Web 服务并检索一长串 XML,然后应用程序将其解析为 NSArrayNSDictionary 对象。 NSArray 包含一个出租公寓信息列表,每个信息都存储在一个NSDictionary 中。

整个列表可能包含 10 种不同类型的公寓(即 2-room、3-room),我们需要根据 Room-Type 将 NSArray 拆分为更小的 NSArrays,其中包含 key " NSDictionary 对象中的 roomType"。

目前我们的算法是

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

但是,第 3 步需要很长时间,因为原始列表可能包含大量 (>100,000) 项。 NSPredicate 似乎遍历了每个键值的整个列表。有没有更有效的方法可以根据 NSDictionary 键将大的 NSArray 拆分为较小的 NSArrays?

【问题讨论】:

    标签: ios nsmutablearray nsdictionary filtering split


    【解决方案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 的回答

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

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

      希望,当客户希望最终数组与输入数组的顺序相同时会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-15
        • 2014-01-22
        • 2011-09-16
        • 1970-01-01
        • 1970-01-01
        • 2010-10-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多