6
\$\begingroup\$

I need to split one NSArray into NSDictionary. Every key in NSDictionary will contain an NSArray with the object with the same value.

i.e. I have an array with 1000 customers and I want create an NSDictionary based on their zip code.

I wrote this code into an NSArray category and it works, but I'm looking for a better name and a way (if it exists) to do the same job with the KVC.

-(NSDictionary *)groupArrayWithBlock:(id<NSCopying> (^)(id obj))block {
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

    for (id obj in self) {
        id<NSCopying> key = block(obj);
        if (! dictionary[key]) {
            NSMutableArray *arr = [NSMutableArray array];
            dictionary[key] = arr;
        }
        [dictionary[key] addObject:obj];
    }
    return [dictionary copy];
}
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

As far as name of the method is concerned I have two points:

  • There is no need of the work Array here, as it is NSArray instance method.
  • The work With gives wrong impression here. (the phrase "group a with b" will generally mean to group them together).

So in my opinion groupUsingBlock or dictionaryGroupedUsingBlock, might be better.

Regarding KVC, if grouping is required to be done on a single property and that property is in complaint with the standard, you can have the function as following:

 -(NSDictionary *)groupByKey:(NSString *) key {
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

    for (id obj in self) {
        id keyValue = [obj valueForKey:key];
        NSMutableArray *arr = dictionary[keyValue];
        if (! arr) {
            arr = [NSMutableArray array];
            dictionary[keyValue] = arr;
        }
        [arr addObject:obj];
    }
    return [dictionary copy];
}

This will make the method slightly easy to use, but will also seriously limit the flexibility. So I would suggest that you keep the method which uses Block and implement the KVC version of the method by using it, like following:

 -(NSDictionary *)groupByKey:(NSString *) key {
    return [self groupUsingBlock:^(id obj) {
            return [obj valueForKey:key];
        }];
}
\$\endgroup\$
1
  • \$\begingroup\$ Thank you and thanks to Jamal for fixing my poor english :). The code is available here: github.com/ignazioc/GroupNSarray and i think it's really usefull for create indexed tableview or somethinkg like this. \$\endgroup\$
    – TheObjCGuy
    Commented Jan 21, 2014 at 20:14
0
\$\begingroup\$

Why not form a method based around enumerateOptionsUsingBlock? More specifically, if you use enumerateObjectsWithOptions:usingBlock, you can specify NSEnumerationConcurrent which will make the processing much faster (which given you have an array with 1000 entries, it sounds like you may need).

Just an idea for an improvement, as the answer here seems to work fine :)

\$\endgroup\$
1
  • \$\begingroup\$ i'm afraid that the speedup isn't very appreciable. I tried with one million of item and execution time was 0.516586 and with the concurrent option the time was 0.464959...by the way...i have even a bizarre error on creaing the array. (see my original post) \$\endgroup\$
    – TheObjCGuy
    Commented Feb 5, 2014 at 18:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.