< Previous PageNext Page > Hide TOC

Sorting and Filtering NSArray Objects

Contents:

Sorting Arrays
Filtering Arrays


Sorting Arrays

There are several ways to sort an NSArray object; these methods return a new array: sortedArrayUsingDescriptors:, sortedArrayUsingFunction:context:, sortedArrayUsingFunction:context:hint:, and sortedArrayUsingSelector:—you can use them with an immutable or a mutable array; these methods sort the contents of a mutable array: sortUsingDescriptors:, sortUsingFunction:context:, and sortUsingSelector:.

Important: If you sort a list that is to be shown to the end user, you should always use a localized comparison.

For a general overview of the issues related to sorting, see Collation Introduction.

Sorting With Functions and Selectors

The following example illustrates the use of sortedArrayUsingSelector:,sortedArrayUsingFunction:context:, and sortedArrayUsingFunction:context:hint:. The most complex of these methods is sortedArrayUsingFunction:context:hint:. The hinted sort is most efficient when you have a large array (N entries) that you sort once and then change only slightly (P additions and deletions, where P is much smaller than N). You can reuse the work you did in the original sort by conceptually doing a merge sort between the N “old” items and the P “new” items. To obtain an appropriate hint, you use sortedArrayHint when the original array has been sorted, and keep hold of it until you need it (when you want to re-sort the the array after it has been modified).

NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
    if ((NSInteger *)reverse == NO) {
        return [string2 localizedCaseInsensitiveCompare:string1];
    }
    return [string1 localizedCaseInsensitiveCompare:string2];
}
 
NSMutableArray *anArray =
    [NSMutableArray arrayWithObjects:@"aa", @"ab", @"ac", @"ad", @"ae", @"af", @"ag",
        @"ah", @"ai", @"aj", @"ak", @"al", @"am", @"an", @"ao", @"ap", @"aq", @"ar", @"as", @"at",
        @"au", @"av", @"aw", @"ax", @"ay", @"az", @"ba", @"bb", @"bc", @"bd", @"bf", @"bg", @"bh",
        @"bi", @"bj", @"bk", @"bl", @"bm", @"bn", @"bo", @"bp", @"bq", @"br", @"bs", @"bt", @"bu",
        @"bv", @"bw", @"bx", @"by", @"bz", @"ca", @"cb", @"cc", @"cd", @"ce", @"cf", @"cg", @"ch",
        @"ci", @"cj", @"ck", @"cl", @"cm", @"cn", @"co", @"cp", @"cq", @"cr", @"cs", @"ct", @"cu",
        @"cv", @"cw", @"cx", @"cy", @"cz", nil];
// note: anArray is sorted
NSData *sortedArrayHint = [anArray sortedArrayHint];
 
[anArray insertObject:@"be" atIndex:5];
 
NSArray *sortedArray;
 
// sort using a selector
sortedArray =
        [anArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
 
// sort using a function
int reverseSort = NO;
sortedArray =
        [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
 
// sort with a hint
sortedArray =
        [anArray sortedArrayUsingFunction:alphabeticSort
                                  context:&reverseSort
                                     hint:sortedArrayHint];

Sorting With Sort Descriptors

Sort descriptors (instances of NSSortDescriptor) provide a convenient and abstract way to describe a sort ordering. Sort descriptors provide several useful features. You can use them in conjunction with Cocoa bindings to sort the contents of, for example, a table view, and you can use them with Core Data to order the results of a fetch request.

If you use the methods sortedArrayUsingDescriptors: or sortUsingDescriptors:, sort descriptors provide an easy way to sort a collection of objects using a number of their properties. Consider the following example. Given an array of dictionaries (custom objects would work in the same way):

NSString *LAST = @"lastName";
NSString *FIRST = @"firstName";
 
NSMutableArray *array = [NSMutableArray array];
NSArray *sortedArray;
 
NSDictionary *dict;
dict = [NSDictionary dictionaryWithObjectsAndKeys:
                     @"Jo", FIRST, @"Smith", LAST, nil];
[array addObject:dict];
 
dict = [NSDictionary dictionaryWithObjectsAndKeys:
                     @"Joe", FIRST, @"Smith", LAST, nil];
[array addObject:dict];
 
dict = [NSDictionary dictionaryWithObjectsAndKeys:
                     @"Joe", FIRST, @"Smythe", LAST, nil];
[array addObject:dict];
 
dict = [NSDictionary dictionaryWithObjectsAndKeys:
                     @"Joanne", FIRST, @"Smith", LAST, nil];
[array addObject:dict];
 
dict = [NSDictionary dictionaryWithObjectsAndKeys:
                     @"Rupert", FIRST, @"Psmith", LAST, nil];
[array addObject:dict];

you can sort the contents of the array by last name then first name as follows:

// The results are likely to be shown to a user
// Note the use of the localizedCaseInsensitiveCompare: selector
NSSortDescriptor *lastDescriptor =
    [[[NSSortDescriptor alloc] initWithKey:LAST
                               ascending:YES
                               selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
NSSortDescriptor *firstDescriptor =
    [[[NSSortDescriptor alloc] initWithKey:FIRST
                               ascending:YES
                               selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
 
NSArray *descriptors = [NSArray arrayWithObjects:lastDescriptor, firstDescriptor, nil];
sortedArray = [array sortedArrayUsingDescriptors:descriptors];

It is conceptually and programatically easy to change the sort ordering and to arrange by first name then last name:

NSSortDescriptor *lastDescriptor =
        [[[NSSortDescriptor alloc] initWithKey:LAST
                                   ascending:NO
                                   selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
NSSortDescriptor *firstDescriptor =
    [[[NSSortDescriptor alloc] initWithKey:FIRST
                               ascending:NO
                               selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
NSArray *descriptors = [NSArray arrayWithObjects:firstDescriptor, lastDescriptor, nil];
sortedArray = [array sortedArrayUsingDescriptors:descriptors];

In particular, it is straightforward to create the sort descriptors from user input.

By contrast, the following code illustrates the first sorting using a function.

NSInteger lastNameFirstNameSort(id person1, id person2, void *reverse)
{
    NSString *name1 = [person1 valueForKey:LAST];
    NSString *name2 = [person2 valueForKey:LAST];
 
    NSComparisonResult comparison = [name1 localizedCaseInsensitiveCompare:name2];
    if (comparison == NSOrderedSame) {
 
        name1 = [person1 valueForKey:FIRST];
        name2 = [person2 valueForKey:FIRST];
        comparison = [name1 localizedCaseInsensitiveCompare:name2];
    }
 
    if ((BOOL *)reverse == NO) {
        return 0 - comparison;
    }
    return comparison;
}
 
BOOL reverseSort = YES;
sortedArray = [array sortedArrayUsingFunction:lastNameFirstNameSort
    context:&reverseSort];

This approach is considerably less flexible.

Filtering Arrays

iPhone OS Note: The predicate classes—NSPredicate, NSCompoundPredicate, and NSComparisonPredicate—are present only in the Mac OS X version of Foundation.

NSArray and NSMutableArray provide methods to filter array contents. NSArray provides filteredArrayUsingPredicate: which returns a new array containing objects in the receiver that match the specified predicate. NSMutableArray adds filterUsingPredicate: which evaluates the receiver’s content against the specified predicate and leaves only objects that match. These methods are illustrated in the following example. For more about predicates, see Predicate Programming Guide.

NSMutableArray *array =
    [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];
 
NSPredicate *bPredicate =
    [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
    [array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.
 
NSPredicate *sPredicate =
    [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filterUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }


< Previous PageNext Page > Hide TOC


© 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-02-04)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.