Group elements of array on another array

2019-06-14 04:30发布

问题:

I have an array of object and each object have a date. I want to group on another array each object with the same date. My idea is this: sort the array by date of objects, for each object on array do this: if object at index i has the same date of object at index i + 1, add the object at index i to a temporary array; else add object at index i to a temporary array, add the array to my output array and remove all objects from my temporary array.

My code is this:

- (void) group{
NSMutableArray *aux = [[NSMutableArray alloc] init];
MyObject *currentObject;
MyObject *nextObject;

// Sort array
NSArray *sortedArray;
sortedArray = [_storeManager.activities sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    NSDate *first = [(MyObject *)a date];
    NSDate *second = [(MyObject *)b date];
    return [first compare:second];
}];

// Grouping array
if ([sortedArray  count] > 0) {
    for (int i = 0; i < [sortedArray count] -1 ; i++) {
        currentObject = sortedArray[i];
        nextObject = sortedArray[i+1];
        int currentDayObject = [currentObject getDayOfDate];
        int currentMonthObject = [currentObject getMonthOfDate];
        int currentYearObject = [currentObject getYearOfDate];
        int nextDayObject = [nextObject getDayOfDate];
        int nextMonthObject = [nextObject getMonthOfDate];
        int nextYearObject = [nextObject getYearOfDate];
        if ((currentDayObject == nextDayObject) && (currentMonthObject == nextMonthObject) && (currentYearObject == nextYearObject)) {
            [aux addObject:currentObject];
        } else {
            [aux addObject:currentObject];
            [_grouped addObject:aux];
            [aux removeAllObjects];
        }
    }
    [_grouped addObject:aux];
}

Why if I do NSLog(@"items on grouped %d",[_grouped count]); it always return 0?

回答1:

You can do it with filter array with key path it gives you all object with distinct date:

NSArray *distinct = [_storeManager.activities valueForKeyPath:@"@distinctUnionOfObjects.date"]

Now you have to create loop to enumerate all object and filter it with predicate for date:

for(NSString *dateAsString in distinct)
{
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date == %@)", dateAsString];
    NSArray *arrayForTheSameDay = [_storeManager.activities  filteredArrayUsingPredicate: predicate];
}

You just need to amend this code to match your properties.

Extended:

If you want to ignore the time you need to create start date and end date and change the predicate to:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", startDate, endDate];

To create NSDate from string with specific format you can use NSDateFormatter, there are plenty examples how to do that.



回答2:

Suggestion: Use an NSMutableDictionary with the dates as keys and NSMutableArrays as values.

You don't have to sort the initial array. Just walk through it, and for each date you encounter, see if a key of that date is already in the dictionary. If not, create an array and add it to the dictionary with the date as the key. If the date is found, get the array corresponding to the key and add the new object to it.

At the end you should have an NSMutableDictionary with all the various dates as keys, and all the corresponding objects as values of those keys. Think of it as a frequency analysis.

As for your question on the grouped count being zero, sorry, I didn't follow the code.