AndyV AndyV - 4 months ago 36
iOS Question

Split NSArray into sub-arrays based on NSDictionary key values

We have an app that calls a SOAP web service and retrieves a long list of XML, which the app then parses into an

NSArray
of
NSDictionary
objects. The
NSArray
contains a list of Rental Apartment information, each of which is stored into an
NSDictionary
.

The entire list may contain 10 different types of Apartments (i.e. 2-room, 3-room), and we need to split the
NSArray
into smaller
NSArray
s based on Room-Type, which has the key "roomType" in the
NSDictionary
objects.

Currently our algorithm is


  1. Use
    [NSArray valueForKeyPath:@"@distinctUnionofObjects.room-type"]

    to obtain a list of unique room-type values.

  2. Loop through the list of unique room-type values

  3. For each unique room-type value, use
    NSPredicate
    to retrieve matching items from the Original list



Our code is below (renamed for clarity):

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


However, step 3 is taking a long time as the original list may contain large amount (>100,000) of items. It seems that
NSPredicate
goes through the entire list for each key value. Is there a more efficient way of splitting a large
NSArray
into smaller
NSArray
s, based on
NSDictionary
keys?

Answer

If the order of your splited Arrays is not important, i have a solution for you:

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