I would create a new class called ItemGroup
, and then add an extra ivar called group
to your item class:
@interface ItemGroup : NSObject
{
NSNumber * time;
}
@property (nonatomic, copy) time;
@end
@interface ItemClass : NSobject
{
NSString * name;
NSNumber * time;
ItemGroup * group;
}
@property (nonatomic, copy) NSString * name;
@property (nonatomic, copy) NSNumber * time;
@property (nonatomic, assign) ItemClass * group; // note: must be assign
@end
Then, you could do the following:
NSMutableDictionary * groups = [NSMutableDictionary dictionaryWithCapacity:0];
for (ItemClass * item in sourceData)
{
ItemGroup * group = [groups objectForKey:item.name];
if (group == nil)
{
group = [[ItemGroup alloc] init];
[groups setObject:group forKey:item.name];
[group release];
group.time = item.time;
}
else if (item.time < group.time)
{
group.time = item.time;
}
item.group = group;
}
This code loops through the unsorted array, keeping track of the minimum time for each group, and also setting the group for each item. With that complete, you simply sort on group.time
and time
:
NSSortDescriptor * groupSorter;
groupSort = [NSSortDescriptor sortDescriptorWithKey:@"group.time" ascending:YES];
NSSortDescriptor * timeSorter;
timeSort = [NSSortDescriptor sortDescriptorWithKey:@"time" ascending:YES];
NSArray * sortDescriptors = [NSArray arrayWithObjects:groupSort, timeSort, nil];
NSArray * sorted = [sourceData sortedArrayUsingDescriptors:sortDescriptors];
And that should do the trick!
UPDATE: Note that you could get much better performance if you were able to assign the groups straight out of the gate. Something like this:
@interface ItemGroup : NSObject
{
NSString * name;
NSNumber * time;
}
@property (nonatomic, copy) NSString * name;
@property (nonatomic, copy) NSSNumber * time;
@end
@interface ItemClass : NSObject
{
ItemGroup * group;
NSNumber * time;
}
@property (nonatomic, retain) ItemGroup * group;
@property (nonatomic, copy) NSNumber * time;
@end
Now, if you maintain a list of groups somewhere (they could even go in an array somewhere, if need be):
ItemGroup * group_A = [[ItemGroup alloc] init];
group_A.name = @"A";
ItemGroup * group_B = [[ItemGroup alloc] init];
group_B.name = @"B";
...
And instead of setting the names of your data items, you set their group:
someItem.group = group_A;
someItem.time = GetSomeRandomTimeValue();
[sourceData addObject:someItem];
....
This would greatly simplify the loop used to set group times:
for (ItemClass * item in sourceData)
{
if (item.time < group.time) { group.time = item.time; }
}
And, if you really wanted to be blazing fast about it, you could even modify the property setter for your time
property to set the group times on the fly:
@implementation ItemClass
- (void)setTime:(NSNumber *)newTime
{
if (newTime < group.time) { group.time = newTime; }
time = [newTime copy];
}
@end
Note that you would have to be sure that group
had been set before you set the time. With this in place, you wouldn't need that sorting loop at all. The sortDescriptors would be enough.