Rebuild an Nsarray by Grouping Objects That Have Matching Id Numbers

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

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

Add objects to NSMutable array with grouping

Okay, so you have an array of items, and you want to group them into sections based on a particular key.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"MM/dd/yyyy"];

// Sparse dictionary, containing keys for "days with posts"
NSMutableDictionary *daysWithPosts = [NSMutableDictionary dictionary];

[myPosts enumerateObjectsUsingBlock:^(PFObject *object, NSUInteger idx, BOOL *stop) {

NSString *dateString = [formatter stringFromDate:[object createdAt]];

// Check to see if we have a day already.
NSMutableArray *posts = [daysWithPosts objectForKey: dateString];

// If not, create it
if (posts == nil || (id)posts == [NSNull null])
{
posts = [NSMutableArray arrayWithCapacity:1];
[daysWithPosts setObject:posts forKey: dateString];
}

// add post to day
[posts addObject:obj];
}];

// Sort Dictionary Keys by Date
NSArray *unsortedSectionTitles = [daysWithPosts allKeys];
NSArray *sortedSectionTitles = [unsortedSectionTitles sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDate *date1 = [formatter dateFromString:obj1];
NSDate *date2 = [formatter dateFromString:obj2];
return [date2 compare:date1];
}];

NSMutableArray *sortedData = [NSMutableArray arrayWithCapacity:sortedSectionTitles.count];

// Put Data into correct format:
[sortedSectionTitles enumerateObjectsUsingBlock:^(NSString *dateString, NSUInteger idx, BOOL *stop) {
NSArray *group = daysWithPosts[dateString];
NSDictionary *dictionary = @{ @"date":dateString,
@"group":group };
[sortedData addObject:dictionary];
}];

self.sampleData = sortedData;

This code will not generate exactly what you asked for. It will generate something that looks like this:

sampleData = @[ @{ @"date": @"12/5/2014",
@"group": @@[ PFObject*,
PFObject*,
PFObject*,
PFObject*,
PFObject*,
]
},
@{ @"date": @"12/3/2014",
@"group": @[ PFObject*,
PFObject*,
PFObject*,
PFObject*,
PFObject
]
}
];

There's no need to convert your PFObject* in the myPosts array into @{ @"text": @"post5", @"location": @"x,y" } since you'll lose access to other pieces of information. Here is how you would use this sampleData array.

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; {
return self.sampleData.count;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; {
return self.sampleData[section][@"date"];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; {
return self.sampleData[section][@"group"].count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; {

PFObject *post = self.sampleData[indexPath.section][@"group"][indexPath.row];
UITableViewCell *cell = // dequeue A reusable tableviewcell here

// configure the cell here

return cell;
}

How to implement group by values in NSMutableArray?

Shanti's answer is close. You want to use the Key-Value Coding collection operator @distinctUnionOfObjects. Place the operator immediately preceding the key which you want it to affect, as if it is a part of the key path you are accessing:

[logMuArray valueForKeyPath:@"@distinctUnionOfObjects.log_date"]

Notice the use of valueForKeyPath:, not valueForKey: The former is a method in the Key-Value Coding protocol, and allows accessing arbitrary depth of attributes. The key path is an NSString made up of dot-separated keys. The result of each key lookup is used in turn to access the next key (starting with the original receiver); by default, valueForKey: is simply called at each step.

iOS how to place header in collection view of date between photos as in iPhone photos app

NSArray<PHAsset *> *imageAssets = @[];
NSMutableDictionary<NSString *, NSMutableArray *> *groupedAssets = [NSMutableDictionary dictionary];
for (PHAsset *imageAsset in imageAssets) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"MMM dd, yyyy"];
NSString *key = [dateFormatter stringFromDate:imageAsset.creationDate];

// Add asset to group
NSMutableArray *group = [groupedAssets objectForKey:key];
if (!group) {
group = [NSMutableArray array];
[groupedAssets setObject:group forKey:key];
}
[group addObject:imageAsset];
}

This is an idea about how can you approach your problem. Above code assumes that you have an array of PHAssets. The groupedAssets object you receive at the end of the loop is collection of assets grouped by day.



Related Topics



Leave a reply



Submit