Sort It Out – Sorting an Array in Swift

I had a question come to me today regarding sorting an array of integers that are actually encoded as strings in the array.  Data comes to is in a variety of encodings/types, so it’s quite common to need to adjust things to the right state for working with.  Let’s take a look at how to solve this one.

The Dilemma

Given an array like this…

1let arrayOfIntsAsStrings = ["103", "2", "1", "50", "55", "98"]

… the question arises:  “How do I sort this in numerical order so that my output array is still an array of strings, but sorted like this ["1”, "2”, "50”, "55”, "98”, "103”, "1000”] (integer comparison), not this ["1”, "1000”, "103”, "2”, "50”, "55”, "98”]  (string comparison)?” Enter Swift’s sorted function:

“Swift’s standard library provides a function called sorted, which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sorted function returns a new array of the same type and size as the old one, with its elements in the correct sorted order. The original array is not modified by the sorted function.” Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.

This is exactly what we need to do the job here.

The Gist

Given the original array outlined above, we can create a new sorted array like this:

1let sortedArray = sorted(arrayOfIntsAsStrings, {
2    (str1: String, str2: String) -> Bool in
3    return str1.toInt() < str2.toInt()

This code produces our desired output:  ["1&#8221;, "2&#8221;, "50&#8221;, "55&#8221;, "98&#8221;, "103&#8221;, "1000&#8221;]

The Details

Swift’s sorted function takes two arguments:  an Array, and a Closure.  The part that may be confusing is the closure argument.  Isolated it looks like this:

2    (str1: String, str2: String) -> Bool in
3    return str1.toInt() < str2.toInt()

Swift provides several shorthand forms of the closure syntax, but I’ve chosen the longest-form here just for full exposure and clarity.  The closure I’ve written simply needs to compute a Bool value representing the result of a comparison between two values – in this case, I’m wanting to do integer comparison, so I write this:  str1.toInt() and str2.toInt().

You can choose whatever parameter names you’d like, and you can actually rely on Type Inference in the parameter section — the compiler can work out what Types your parameters are.  But if it helps clue you in to what the code is doing, you can specify the Types in the closure’s parameter section, as I wrote about recently, and as I did in my example when I wrote str1: String, str2: String (I could have left off the : String).

Within the closure’s body, you can put in as many lines of logic as are necessary in order to produce an appropriate comparison result to get your Array in the right order.  If it gets too complicated to do it in-line, think about encapsulating that logic inside one or more functions in the spirit of writing clean code.

To produce an appropriate comparison result, you’ll have to consider the Types of the data you’re working with within the closure and consider any casting or manipulation you’ll need to do to produce the correct result like we did in our example. Other than that, it’s pretty straightforward to sort it out!

comments powered by Disqus