I have a question about sorting NSMutableArray
. I can use sortedArrayUsingDescriptors:
method to sort an array with objects.
For example I have an NSMutableArray
of places
where I have an attribute frequency
(int value) and I want to sort descending on frequency
but I don't know how to use it correctly.
What do I put as a key in initWithKey
?
My object place
contains:
NSString * name; NSString * address; NSString * frequency; NSString * type;
NSMutableArray * places; ... populate array with objects ... NSSortDescriptor * sortByFrequency = [[[NSSortDescriptor alloc] initWithKey:@"????????" ascending:NO] autorelease]; NSArray * descriptors = [NSArray arrayWithObject:sortByFrequency]; NSArray * sorted = [x sortedArrayUsingDescriptors:descriptors];
The trick to sorting an array is a method on the array itself called "sortedArrayUsingDescriptors:". The method takes an array of NSSortDescriptor objects. These descriptors allow you to describe how your data should be sorted.
For just sorting array of strings: sorted = [array sortedArrayUsingSelector:@selector(compare:)]; For sorting objects with key "name": NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(compare:)]; sorted = [array sortedArrayUsingDescriptors:@[sort]];
The NSMutableArray class declares the programmatic interface to objects that manage a modifiable array of objects. This class adds insertion and deletion operations to the basic array-handling behavior inherited from NSArray . NSMutableArray is “toll-free bridged” with its Core Foundation counterpart, CFMutableArray .
To sort your array of objects you:
NSSortDescriptor
- use names of your variables as keys to setup descriptor for sorting plus the selector to be executed on those keysNSSortDescriptor
that you've setupHere are two examples, one using NSDictionary
and NSString/NSNumber
values sorting on NSNumber
, the other one using custom class with sorting on two NSString
fields.
Follow Sorting and Filtering NSArray Objects in Cocoa programming topics to see more examples and explanation.
Example:
This was done on GNUStep it should work the same on Cocoa - the code is exactly the same - I'll try when I sit in front of my Mac:
First example using NSString
and NSNumber
values with sorting on NSNumber
value:
NSString * NAME = @"name"; NSString * ADDRESS = @"address"; NSString * FREQUENCY = @"frequency"; NSString * TYPE = @"type"; NSMutableArray * array = [NSMutableArray array]; NSDictionary * dict; dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Alehandro", NAME, @"Sydney", ADDRESS, [NSNumber numberWithInt:100], FREQUENCY, @"T", TYPE, nil]; [array addObject:dict]; dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Xentro", NAME, @"Melbourne", ADDRESS, [NSNumber numberWithInt:50], FREQUENCY, @"X", TYPE, nil]; [array addObject:dict]; dict = [NSDictionary dictionaryWithObjectsAndKeys: @"John", NAME, @"Perth", ADDRESS, [NSNumber numberWithInt:75], FREQUENCY, @"A", TYPE, nil]; [array addObject:dict]; dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Fjord", NAME, @"Brisbane", ADDRESS, [NSNumber numberWithInt:20], FREQUENCY, @"B", TYPE, nil]; [array addObject:dict];
Sorting part using descriptors with the Frequency field which is NSNumber
:
NSSortDescriptor * frequencyDescriptor = [[[NSSortDescriptor alloc] initWithKey:FREQUENCY ascending:YES] autorelease]; id obj; NSEnumerator * enumerator = [array objectEnumerator]; while ((obj = [enumerator nextObject])) NSLog(@"%@", obj); NSArray * descriptors = [NSArray arrayWithObjects:frequencyDescriptor, nil]; NSArray * sortedArray = [array sortedArrayUsingDescriptors:descriptors]; NSLog(@"\nSorted ..."); enumerator = [sortedArray objectEnumerator]; while ((obj = [enumerator nextObject])) NSLog(@"%@", obj);
OUTPUT - sorted by Frequency field:
2009-12-04 x[1] {address = Sydney; frequency = 100; name = Alehandro; type = T; } 2009-12-04 x[1] {address = Melbourne; frequency = 50; name = Xentro; type = X; } 2009-12-04 x[1] {address = Perth; frequency = 75; name = John; type = A; } 2009-12-04 x[1] {address = Brisbane; frequency = 20; name = Fjord; type = B; } 2009-12-04 x[1] Sorted ... 2009-12-04 x[1] {address = Brisbane; frequency = 20; name = Fjord; type = B; } 2009-12-04 x[1] {address = Melbourne; frequency = 50; name = Xentro; type = X; } 2009-12-04 x[1] {address = Perth; frequency = 75; name = John; type = A; } 2009-12-04 x[1] {address = Sydney; frequency = 100; name = Alehandro; type = T; }
Second example with custom class and sorting on two NSString
variables.
Array to sort (see class A
at the bottom):
NSMutableArray * array = [NSMutableArray array]; [array addObject:[[A alloc] initWithFirstName:@"Alehandro" lastName:@"Xentro" age:[NSNumber numberWithInt:40]]]; [array addObject:[[A alloc] initWithFirstName:@"John" lastName:@"Smith" age:[NSNumber numberWithInt:30]]]; [array addObject:[[A alloc] initWithFirstName:@"John" lastName:@"Smyth" age:[NSNumber numberWithInt:25]]]; [array addObject:[[A alloc] initWithFirstName:@"Torro" lastName:@"Ola" age:[NSNumber numberWithInt:45]]]; [array addObject:[[A alloc] initWithFirstName:@"Alehandro" lastName:@"Bento" age:[NSNumber numberWithInt:41]]]; [array addObject:[[A alloc] initWithFirstName:@"Alehandro" lastName:@"Axel" age:[NSNumber numberWithInt:41]]];
The sorting part, sort on lastName then firstName:
NSString * LASTNAME = @"lastName"; NSString * FIRSTNAME = @"firstName"; NSSortDescriptor *lastDescriptor = [[[NSSortDescriptor alloc] initWithKey:LASTNAME ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease]; NSSortDescriptor *firstDescriptor = [[[NSSortDescriptor alloc] initWithKey:FIRSTNAME ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease]; NSArray * descriptors = [NSArray arrayWithObjects:lastDescriptor, firstDescriptor, nil]; NSArray * sortedArray = [array sortedArrayUsingDescriptors:descriptors];
Print the result:
NSLog(@"\nSorted ..."); enumerator = [sortedArray objectEnumerator]; while ((obj = [enumerator nextObject])) NSLog(@"%@", obj);
Result (before and after sorting):
2009-12-04 00:52:16.637 x[11375] Alehandro, Xentro, age:40 2009-12-04 00:52:16.644 x[11375] John, Smith, age:30 2009-12-04 00:52:16.644 x[11375] John, Smyth, age:25 2009-12-04 00:52:16.644 x[11375] Torro, Ola, age:45 2009-12-04 00:52:16.645 x[11375] Alehandro, Bento, age:41 2009-12-04 00:52:16.645 x[11375] Alehandro, Axel, age:41 2009-12-04 00:52:16.645 x[11375] Sorted ... 2009-12-04 00:52:16.645 x[11375] Alehandro, Axel, age:41 2009-12-04 00:52:16.645 x[11375] Alehandro, Bento, age:41 2009-12-04 00:52:16.645 x[11375] Torro, Ola, age:45 2009-12-04 00:52:16.645 x[11375] John, Smith, age:30 2009-12-04 00:52:16.645 x[11375] John, Smyth, age:25 2009-12-04 00:52:16.645 x[11375] Alehandro, Xentro, age:40
Class A
extends NSObject
- nothing special here:
#import <Foundation/Foundation.h> @interface A : NSObject { NSString * firstName; NSString * lastName; NSNumber * age; } - (id)initWithFirstName:(NSString*)aFirstName lastName:(NSString*)aLastName age:(NSNumber*)anAge; -(NSString* )description; +(NSString*)action; @end
Implementation:
#import <Foundation/Foundation.h> #import "A.h" @implementation A - (id)init { return [self initWithFirstName:@"N/A" lastName:@"N/A" age:0]; } - (id)initWithFirstName:(NSString*)aFirstName lastName:(NSString*)aLastName age:(NSNumber*)anAge { self = [super init]; if (!self) return nil; firstName = [aFirstName copy]; lastName = [aLastName copy]; age = [anAge copy]; return self; } - (void)dealloc { [firstName release]; [lastName release]; [age release]; [super release]; }
- (NSString *) description { return [NSString stringWithFormat: @"%@, %@, age:%@", firstName, lastName, age]; } @end
The "key" is a method of your objects (the elements of your array "x") that returns the thing you want to sort by. So in this case, you said that you want to sort by the "frequency". Then all you have to do is use the name of the method that returns the frequency, as the key.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With