Grouping of Custom Objects in Objective-C

I have and array of custom objects of Person Class

Person : NSObject{
    NSString *firstName;
    NSString *lastName; 
    NSString *age;
}

NSMutableArray *personsArray = [NSMutableArray array];
Person  *personObj1 =  [[[Person alloc]  init] autorelease];
personObj1.firstName = @"John";
personObj1.lastName = @"Smith";
personObj1.age = @"25";
[personsArray addObject: personObj1];

Person  *personObj2 =  [[[Person alloc]  init] autorelease];
personObj2.firstName = @"John";
personObj2.lastName = @"Paul";
personObj2.age = @"26";
[personsArray addObject: personObj2];

Person  *personObj3 =  [[[Person alloc]  init] autorelease];
personObj3.firstName = @"David";
personObj3.lastName = @"Antony";
personObj3.age = @"30";
[personsArray addObject: personObj3];

Now personsArray contains 3 objects of Person objects.

  • didSelectRowAtIndexPath: not being called
  • Facebook in iPhone app
  • Can i change multiplier property for NSLayoutConstraint?
  • Do OCUnit and OCMock work on the iPhone SDK?
  • Getting wrong carrier name in IOS
  • Swift: Does not conform to protocol NSCoding
  • Can we group this objects by attribute like age or firstName ?

    My expected result is

    NSDictionary {
        "John" = >{
            personObj1, //(Its  because personObj1 firstName is John )
            personObj2 //(Its  because personObj2 firstName is John )
        },
        "David" = >{
            personObj3, //(Its  because personObj3 firstName is David )
        },
    }
    

    I know I can get this result by creating an NSDictionary and then Iterate through personsArray, then check for each first

    NSMutableDictionary *myDict = [NSMutableDictionary dictionary];
    
      for (Person *person in personsArray){
    
        if([myDict objectForKey: person.firstName]){
            NSMutableArray *array = [myDict objectForKey: person.firstName];
            [array addObject:person];
            [myDict setObject: array forKey:person.firstName];
        }else{
            NSMutableArray *array = [NSMutableArray arrayWithObject:person];
            [myDict setObject: array forKey:person.firstName];
        }
        }
    
        NSLog(@"myDict %@", myDict);
    
    //Result myDict will give the desired output. 
    

    But is there any better way to do ?

    If I am using @distinctUnionOfObjects , I can group by string objects only (Not such custom objects. Am I right ?).

    Thanks for the answer in advance.

    6 Solutions Collect From Internet About “Grouping of Custom Objects in Objective-C”

    Checkout this answers it is very similar to what you want

    https://stackoverflow.com/a/15375756/1190861

    The code in your case will be as the following:

    NSMutableDictionary *result = [NSMutableDictionary new];
    
    NSArray *distinctNames;
    distinctNames = [personsArray valueForKeyPath:@"@distinctUnionOfObjects.firstName"];
    for (NSString *name in distinctNames) {
        NSPredicate predicate = [NSPredicate predicateWithFormat:@"firstName = %@", name]; 
        NSArray *persons = [personsArray filteredArrayUsingPredicate:predicate];
        [result setObject:persons forKey:name];
    }
    
    NSLog(@"%@", result);
    

    You can try this is custom object sorting for an array

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Firstname" ascending:NO selector:@selector(compare:)];
    
    [Array sortUsingDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
    

    I have created a small library called Linq-to-ObjectiveC which provides a number of methods which make is easier to query arrays. In order to perform the group operation you require you can simply do the following:

    NSDictionary* groupedByName = [personsArray groupBy:^id(id person) {
       return [person firstName];
    }];
    

    This would return a dictionary where the keys are the distinct first names, and each value is an array of ‘person’ objects that have the given first name.

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

    A Drop in code to help you doing it,

        -(NSMutableArray *)sortArray:(NSArray *)arrayTosort withKey:(NSString *)key ascending:(BOOL)_ascending
    {
        NSSortDescriptor *sortDescriptor;
        sortDescriptor = [[NSSortDescriptor alloc] initWithKey:key
                                                     ascending:_ascending] ;
        NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    
        return [[arrayTosort sortedArrayUsingDescriptors:sortDescriptors] mutableCopy];
    }
    

    here key is key or keypath.

    There isn’t a built in group by method in NSArray. Your example implementation could be added as a category.

    Unfortunately, the @distinctUnionOfObjects operation will only return the strings of the firstName property: John, David. It won’t do a group by operation, nor is there such an operation.

    Collection Operations