Rebuild an NSArray by grouping objects that have matching id numbers?

匿名 (未验证) 提交于 2019-12-03 02:08:02

问题:

I have an NSArray and each object in the array has a groupId and a name. Each object is unique but there are many with the same groupId. Is there a way i can tear the array apart and rebuild it so that the names are grouped into a single object with the corresponding groubId? Here is what the array currently looks like:

2013-03-12 20:50:05.572 appName[4102:702] the  array:  (         {         groupId = 1;         name = "Dan";     },         {         groupId = 1;         name = "Matt";     },         {         groupId = 2;         name = "Steve";     },         {         groupId = 2;         name = "Mike";     },         {         groupId = 3;         name = "John";      },         {         groupId = 4;         name = "Kevin";     } )

This is what I would like it to look like:

2013-03-12 20:50:05.572 appName[4102:702] the  array:  (         {         groupId = 1;         name1 = "Dan";         name2 = "Matt";     },         {         groupId = 2;         name1 = "Steve";         name2 = "Mike";     },         {         groupId = 3;         name = "John";      },         {         groupId = 4;         name = "Kevin";     } )

EDIT: I've tried & failed with many attempts, most along the lines of something like this (sloppy recreation, but to give an idea):

int idNum = 0; for (NSDictionary *arrObj in tempArr){     NSString *check1 = [NSString stringWithFormat:@"%@",[arrObj valueForKey:@"groupId"]];     NSString *check2 = [NSString stringWithFormat:@"%@",[[newDict valueForKey:@"groupId"]];     if (check1 == check2){         NSString *nameStr = [NSString stringWithFormat:@"name_%d",idNum];         [newDict setValue:[arrObj valueForKey:@"name"] forKey:nameStr];     }     else {         [newDict setValue:arrObj forKey:@"object"];     }     idNum++; }  

回答1:

NSArray *array = @[@{@"groupId" : @"1", @"name" : @"matt"},                    @{@"groupId" : @"2", @"name" : @"john"},                    @{@"groupId" : @"3", @"name" : @"steve"},                    @{@"groupId" : @"4", @"name" : @"alice"},                    @{@"groupId" : @"1", @"name" : @"bill"},                    @{@"groupId" : @"2", @"name" : @"bob"},                    @{@"groupId" : @"3", @"name" : @"jack"},                    @{@"groupId" : @"4", @"name" : @"dan"},                    @{@"groupId" : @"1", @"name" : @"kevin"},                    @{@"groupId" : @"2", @"name" : @"mike"},                    @{@"groupId" : @"3", @"name" : @"daniel"},                    ];  NSMutableArray *resultArray = [NSMutableArray new]; NSArray *groups = [array valueForKeyPath:@"@distinctUnionOfObjects.groupId"]; for (NSString *groupId in groups) {     NSMutableDictionary *entry = [NSMutableDictionary new];     [entry setObject:groupId forKey:@"groupId"];      NSArray *groupNames = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"groupId = %@", groupId]];     for (int i = 0; i < groupNames.count; i++)     {         NSString *name = [[groupNames objectAtIndex:i] objectForKey:@"name"];         [entry setObject:name forKey:[NSString stringWithFormat:@"name%d", i + 1]];     }     [resultArray addObject:entry]; }  NSLog(@"%@", resultArray);

Output:

    (         {         groupId = 3;         name1 = steve;         name2 = jack;         name3 = daniel;     },         {         groupId = 4;         name1 = alice;         name2 = dan;     },         {         groupId = 1;         name1 = matt;         name2 = bill;         name3 = kevin;     },         {         groupId = 2;         name1 = john;         name2 = bob;         name3 = mike;     }  )


回答2:

This calls for a NSDictionary of NSArrays. There's no quick and elegant way - you'd have to scroll through the source.

NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:10]; //Or use alloc/init for(SomeObject o in appname) //What's the type of objects? you tell me {     NSObject *ID = [o objectForKey: @"groupId"];     NSMutableArray *a = [d objectForKey: ID];     if(a == nil)     {         a = [NSMutableArray arrayWithCapacity: 10];         [d setObject:a forKey: ID];     }     [a addObject: [o objectForKey: @"name"]]; }

EDIT: edited to not assume the datatype of the key.



回答3:

This is similar to Seva's answer, but it can be added as a category method on NSArray:

/// @return A dictionary of NSMutableArrays - (NSDictionary *)abc_groupIntoDictionary:(id<NSCopying>(^)(id object))keyFromObjectCallback {     NSParameterAssert(keyFromObjectCallback);     NSMutableDictionary *result = [NSMutableDictionary dictionary];     for (id object in self) {         id<NSCopying> key = keyFromObjectCallback(object);         NSMutableArray *array = [result objectForKey:key];         if (array == nil) {             array = [NSMutableArray new];             [result setObject:array forKey:key];         }         [array addObject:object];     }     return [result copy]; }

And you can use it like so:

NSDictionary *groups = [people abc_groupIntoDictionary:^id<NSCopying>(NSDictionary *person) {     return person[@"groupId"]; }];

This isn't exactly the same as the original answer since it will preserve the person dictionary as the values in the array, but you can then just read the name property off of that.



回答4:

Swift implementation of Sergery's answer for my fellow noobs.

class People: NSObject {     var groupId: String     var name : String     init(groupId: String, name: String){         self.groupId = groupId         self.name = name     } }   let matt = People(groupId: "1", name: "matt") let john = People(groupId: "2", name: "john") let steve = People(groupId: "3", name: "steve") let alice = People(groupId: "4", name: "alice") let bill = People(groupId: "1", name: "bill") let bob = People(groupId: "2", name: "bob") let jack = People(groupId: "3", name: "jack") let dan = People(groupId: "4", name: "dan") let kevin = People(groupId: "1", name: "kevin") let mike = People(groupId: "2", name: "mike") let daniel = People(groupId: "3", name: "daniel")  let arrayOfPeople = NSArray(objects: matt, john, steve, alice, bill, bob, jack, dan, kevin, mike, daniel)  var resultArray = NSMutableArray() let groups = arrayOfPeople.valueForKeyPath("@distinctUnionOfObjects.groupId") as [String]   for groupId in groups {     var entry = NSMutableDictionary()     entry.setObject(groupId, forKey: "groupId")     let predicate = NSPredicate(format: "groupId = %@", argumentArray: [groupId])     var groupNames = arrayOfPeople.filteredArrayUsingPredicate(predicate)     for i in 0..<groupNames.count {         let people = groupNames[i] as People         let name = people.name         entry.setObject(name, forKey: ("name\(i)"))     }     resultArray.addObject(entry) }  println(resultArray)

Note the @ sign in valueForKeyPath. that tripped me up a little :)



回答5:

The below code will Rebuild an NSArray by grouping objects w.r.t any matching keys in each dictionary in that array

//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);

//Converting from dictionary to array again...

self.finalArray = [[NSMutableArray alloc]init]; for (NSString *uniqueKey in aMutableArray) {    NSDictionary *aUniqueKeyDict = @{@"groupKey":uniqueKey,@"featureValues":[dictFromArray objectForKey:uniqueKey]};    [self.finalArray addObject:aUniqueKeyDict]; }

Hope it may help..



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!