Sorting strings in Swift

Sorting an array of strings in Swift is a bit of an iceberg topic – it seems fairly manageable, you just call the sort function right? Then you dig a little deeper and find a whole lot more lurking under the surface!

Let’s start with the example in Apple’s Swift Programming Language guide:

(Apple sorts the data in reverse order, for simplicity I’ve swapped it)

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let sortedNames = names.sorted(by: { $0 < $1 } )
print(sortedNames)
// Prints "["Alex", "Barry", "Chris", "Daniella", "Ewa"]"

Great, but what happens if “Alex” starts with a lower case letter? Alex gets shunted to the end of the list – probably not what you’re after!
“Barry”, “Chris”, “Daniella”, “Ewa”, “alex”

To ignore case, compare the lower case versions of the names:

let sortedNames = names.sorted(by: {
    $0.lowercased() < $1.lowercased() } )

The rules for ordering strings can vary for different languages and locales. From Apple’s iOS String Programming Guide:

Important: For user-visible sorted lists, you should always use localized comparisons.

Fortunately, strings have another property called localizedLowercase.

let lowercaseSortedNames = names.sorted(by: {
    $0.localizedLowercase &lt; $1.localizedLowercase } )

Now let’s add some complexity to this problem. Let’s say we have a Person class, that contains a first name and a last name, and an array of people:

struct Person {
    var firstName: String
    var lastName: String
}
let people = [
    Person(firstName: "Kylie", lastName: "Minogue"),
    Person(firstName: "Dannie", lastName: "Minogue"),
    Person(firstName: "Paul", lastName: "Kelly"),
    Person(firstName: "Ned", lastName: "Kelly")
]

Sorting them by last name is easy enough, just be sure to include the lastName property:

let sortedPeople = people.sorted(by: {
    $0.lastName.localizedLowercase < $1.lastName.localizedLowercase } )

Screenshot 2016-08-05 12.57.30

Obviously the first names need to be compared as well. You can achieve this by putting the two comparisons into a tuple:

let sortedPeople = people.sorted(by: {
    ($0.lastName.localizedLowercase,$0.firstName.localizedLowercase) <
        ($1.lastName.localizedLowercase,$1.firstName.localizedLowercase)
} )

Screenshot 2016-08-05 13.02.11

Interactive developer, Author - iOS development with Swift - book coming 2017 https://manning.com/books/ios-development-with-swift

Tagged with:
Posted in Swift

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: