Diacticric Insensitive Sorting of NSString Arrays like Addressbook on iPhone

Sorting NSArray of NSStrings Like Addressbook on iPhone Sort

In this article, we will explore how to sort an array of NSStrings in a way similar to the Addressbook app on iPhone. The Addressbook app sorts names with accents (éli, àli, etc.) under the correct letter (E, A, etc.). We will cover the necessary steps and techniques to achieve this diacritic insensitive sorting.

Understanding the Problem

The problem is that standard string comparison methods do not account for diacritics. Accents and other diacritical marks can change the appearance of a character when compared against another. For example, ’e’ and ‘é’ are different characters when it comes to alphabetical order. To sort names like those in the Addressbook app, we need to perform a diacritic insensitive comparison.

Diacritics in NSString

Before diving into the solution, let’s understand how diacritics work in NSString. In Unicode, each character has a unique code point. However, some characters have additional marks that modify their meaning (e.g., accent mark). These marks are called diacritical marks. To handle these marks, we need to decompose them.

In iOS and macOS, NSString uses the decomposedStringWithCanonicalMapping method to decompose a string into its canonical form, removing any diacritical marks. This is what allows us to compare strings without worrying about accents or other marks.

Sorting NSArray of NSStrings

To sort an array of NSStrings like the Addressbook app, we will use Apple’s sortedArrayUsingComparator: method. This method takes a comparator block that defines how two objects should be compared.

In our case, we want to perform a diacritic insensitive comparison. We can achieve this by using the NSDiacriticInsensitiveSearch and NSCaseInsensitiveSearch options when comparing strings.

Here’s an example of how you might implement this:

NSArray *array = [NSArray arrayWithObjects:@"éli", @"bob", @"earl", @"allen", @"àli", nil];

NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch];
}];

However, this will not section the results based on the first character diacritic insensitive. We can achieve this by using a dictionary to group the sorted names.

Sectioning Results

Let’s create an example that sections the results based on the first character of each name:

NSArray *array = [NSArray arrayWithObjects:@"éli", @"bob", @"earl", @"allen", @"àli", nil];

// Sort the array using diacritic insensitive comparison
NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch];
}];

// Create a dictionary to group the sorted names
NSMutableDictionary *sectioned = [NSMutableDictionary dictionary];

// Iterate over the sorted array and add each name to its corresponding section in the dictionary
for (NSString *str in sorted)
{
    if (![str length]) continue; // Ignore empty strings

    NSMutableArray *names = nil;

    // Compare the first character using diacritic insensitive search
    NSString *firstChar = [str decomposedStringWithCanonicalMapping];
    if ([str compare:firstChar options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch range:NSMakeRange(0, 1)] == NSOrderedSame)
    {
        names = [sectioned objectForKey:firstChar];
    }
    else
    {
        // If the character is not in the dictionary, add it and create a new array for it
        firstChar = [[str decomposedStringWithCanonicalMapping] substringToIndex:1];
        names = [NSMutableArray array];
        [sectioned setObject:names forKey:firstChar];
    }

    [names addObject:str];
}

// Print out the sorted array and sectioned dictionary
NSLog(@"sorted: %@", sorted);
NSLog(@"sectioned: %@", sectioned);

Conclusion

In this article, we explored how to sort an array of NSStrings like the Addressbook app on iPhone. We covered the necessary steps and techniques to perform diacritic insensitive sorting. By using Apple’s sortedArrayUsingComparator: method and the decomposedStringWithCanonicalMapping method, we can easily sort arrays of names with accents.


Last modified on 2025-01-27