views:

113

answers:

2

If I have an NSArray with some values in them. Is there a way using descriptors to sort it by the most frequent number in the array first and the least frequent number at the end,

Array has(
"3",
"2",
"1",
"3",
"3",
"7",
)

to

Array has(
"3",
"3",
"3",
"1",
"2",
"7",
)
A: 

Not without some additional data structures.

All the NSArray sorting operations (sortUsingDescriptors:, sortedArrayUsingSelector:, etc.) assume that you can look at two elements "a" and "b" and determine if "a < b" without looking at any other elements in the NSArray.

One solution would be to create a new Array whose member objects contain both the value and the frequency count (use an NSDictionary to efficiently count how many rows there are for each value). For example:

Array( // {value, frequency}
{3,3},
{2,1},
{1,1},
{3,3},
{3,3},
{7,1}
)

Then it's easy to use a descriptor to sort that array by frequency.

David Gelhar
A: 
@interface NSArray (Ext)
-(NSArray*) sortByMostFrequent ;
@end



@implementation NSArray (Ext)
-(NSArray*) sortByMostFrequent {
    NSMutableDictionary* frequencyDict = [NSMutableDictionary dictionary];
    for (id obj in self) {
        int frequency = [[frequencyDict valueForKey:obj] intValue];
        [frequencyDict setValue:[NSNumber numberWithInt:frequency+1] forKey:obj];
    }
    NSMutableArray* ary = [NSMutableArray arrayWithCapacity:self.count];
    for (id obj in self) {
        [ary addObject:[NSDictionary dictionaryWithObjectsAndKeys:
                        obj, @"Object",
                        [frequencyDict valueForKey:obj], @"Frequency",
                        nil]];
    }
    NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Frequency" ascending:NO];
    [ary sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    [sortDescriptor release];
    return [ary valueForKey:@"Object"];
}
@end



/// example
NSArray* ary = [NSArray arrayWithObjects:@"3", @"2", @"1", @"3", @"3", @"7", nil];
NSLog(@"ary %@", [ary sortByMostFrequent]);
wookay