Sorting in Swift
Tags: swift, ios, iosappdevelopment, sorting
Published: 2021-01-18 02:32:35

---
title: Sorting in Swift
published: true
date: 2021-01-18 00:24:17 UTC
tags: Swift,iOS,iosappdevelopment,sorting
canonical_url: https://dilloncodes.com/sorting-in-swift
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/tr3d3tsrzr3nj9nlzcal.jpg
---
{% youtube Jtb_f5EY2DY %}

Sometimes you have a collection of elements that are not in the order that you need them. Fortunately, Swift gives us an easy way to get them from that chaotic state into an ordered state. In this article we're going to look at how to use the sort methods, how we can clean up the code around them, and how we can sort objects that aren't necessarily sortable as a whole.

## Breaking It Down ##
If you've taken a computer science class, or are learning fundamentals, you have probably learned about [insertion sort](https://en.wikipedia.org/wiki/Insertion_sort), [quicksort](https://en.wikipedia.org/wiki/Quicksort) or [merge sort](https://en.wikipedia.org/wiki/Merge_sort) or one of the others and how to implement them. That's good stuff to know, but in practice we don't usually want to think at that level because we are likely to make mistakes in our code and there is almost always a way to optimize things further beyond what we know. So Swift has these two methods `sort(by:)` and `sorted(by:)`. They provide an abstraction around what sorting method is used, so you don't have to care. They just ask you for a closure that they can call on any two elements and you have to return a boolean that lets the sort function know if those two elements are in increasing order.

```swift
mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows
func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
```

Let's dig into that, but first I just want to note that the main difference between them is  `sort` sorts your collection in place and `sorted` returns a new array with the elements sorted. I almost always use `sorted`, but there are times when performance can be improved significantly by using `sort` instead, so it is good to keep in the back of your head. For the rest of this article, I'm only going to refer to `sorted`.

Looking at the function signature might be a little intimidating. I know it was for me when I was first trying to read the documentation. I mean, what is `rethrows`? It turns out, the `throws` and `rethrows` in this context are things you can ignore until you need them. (If you can't stand not knowing, check out [Paul Hudson's article on the topic](https://www.hackingwithswift.com/example-code/language/how-to-use-the-rethrows-keyword).) So let's just pretend that this is the signature:
```swift
func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element]
```
This is a function which you can call on a collection, it's only parameter is a closure that takes two `Element`s and returns a `Bool`, and the function itself returns an `[Element]`. The closure is where you tell the sorter how to sort.  It might look something like this:

```swift
let unsortedArray = [3, 2, 5, 1, 4]

let goingUp = unsortedArray.sorted(by: { first, second -> Bool in
    return first < second
})
// goingUp == [1, 2, 3, 4, 5]

let goingDown = unsortedArray.sorted(by: { first, second -> Bool in
    return first > second
})
// goingDown == [5, 4, 3, 2, 1]
```

So whatever method is actually used for sorting, it will go through and any time it needs to make a decision of "should _this_ element go first or _that_ one?" it will call this closure and based on the answer it will know where each element needs to go. This is already pretty powerful, but it gets even better. 

## Same Thing, But Shorter
We can communicate the same thing in way fewer characters because of some nice syntactic sugar in Swift. Let's see all the steps we can take to reduce our code here.

First, we can make it a trailing closure and get rid of the argument label.
```swift
let goingUp = unsortedArray.sorted() { first, second -> Bool in
    return first < second
}
```

We can get rid of the return type definition, because the sorted method already has that as a part of its signature so it can be inferred here. If you try to write a closure here that doesn't return a boolean, the compiler will complain.
```swift
let goingUp = unsortedArray.sorted() { first, second in
    return first < second
}
```

Because this is one line, we can also get rid of the `return` keyword at the end of the closure. The compiler will assume that you intend to return the result of this line (as long as it evaluates to a boolean).
```swift
let goingUp = unsortedArray.sorted() { first, second in
    first < second
}
```

We also get some free parameter names that are based on the argument position in the closure, so we can get rid of the parameter names too. `$0` will be the first argument, counting up from there.
```swift
let goingUp = unsortedArray.sorted() {
    $0 < $1
}
```

We can also get rid of the parentheses because there are no other arguments except this trailing closure. At the same time, this is so short we can even fit it on one line.
```swift
let goingUp = unsortedArray.sorted { $0 < $1 }
```

That is much shorter, and it puts the central logic right in front of you. We're sorting in the order where the smaller elements will come first. But don't feel bad if you get mixed up with such short statements, especially when it hasn't made it into your muscle memory yet. I think it is a good practice to start with the fully expanded version while you're working the logic out and then go through these steps to try to condense it from there. Over time, it will become second nature for you.

In this case, we can actually take it even farther. Because operators in Swift are basically just special syntax for functions, and functions are themselves closures, and because the signature for `<` matches the signature for the closure we're looking for in `sorted`, as long as the elements in our array are `Comparable` we can just pass the operator as the parameter.
```swift
let goingUp = unsortedArray.sorted(by: <)
```

Last but not least, if we want to sort in ascending order (which we do in this case) and our elements are `Comparable`, we don't actually have to provide any argument because that is the default.
```swift
let goingUp = unsortedArray.sorted()
```

## Sorting On Properties
Another thing that makes `sorted` so powerful is that you don't have to sort on the whole element, you can sort on one of its properties instead. This is super helpful because it is not uncommon to have an object where the whole object is not `Comparable`, but some of its properties are. For example, think about how you would sort a group of people. Would you sort them by age? or by name? by height? Whatever you chose, you would almost certainly sort them by some specific attribute (or combination of attributes), not by them as whole people. It’s hard to even imagine what that would mean. Besides that, in some contexts it may make sense to sort them by name, but in others it may make more sense to sort them by interest, or height, or hair color. And the same is true in our code. Fortunately, Swift makes this really easy to do.
```swift
struct Person {
    let name: String
    let createdAt: Date = Date()
}
let wayne = Person(name: "Wayne")
let derry = Person(name: "Derry")
let dan = Person(name: "Dan")

let unsortedPeople = [dan, wayne, derry]

let alphabetical = unsortedPeople.sorted { $0.name < $1.name }
// alphabetical == [dan, derry, wayne]

let oldestFirst = unsortedPeople.sorted { $0.createdAt < $1.createdAt }
// oldestFirst == [wayne, derry, dan]
```

In the first example, we sort on the person's name and the second we sort on the date when that person was created.  If your object has further nested properties, you could sort on those too! It just comes down to whatever makes the most sense in your use case. And that is the beauty of `sorted`. You don't have to worry about _how_ to sort elements, you only have to think about _what_ you want to sort them by.

For some extra sugar, you can even add [a simple extension that I picked up from John Sundell](https://www.swiftbysundell.com/articles/the-power-of-key-paths-in-swift/) that will let you sort on a keypath. I won't go into detail here about what keypaths are or how to use them, but check out John's article if you're interested. Here's what that looks like.
```swift
extension Sequence {
    func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>) -> [Element] {
        sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
    }
}

let alphabetical = unsortedPeople.sorted(by: \.name)
// alphabetical == [dan, derry, wayne]
```

A couple of things to note about this extension. First, this method assumes that you want to sort in ascending order, but you can customize it however makes sense for your use case. You could even further extend it to also take in a closure so that the sort order could be defined at the call site. But I'll leave that as an exercise for you to try out if you want.

Second, notice that the extension is on `Sequence`, not on `Array`. This is because of another very powerful feature of Swift, the collection protocols. Again, I'm not going to go into a ton of detail here, but check out [Harshil Shah's article on Swift's Collection Types](https://harshil.net/blog/swift-sequence-collection-array). It is about as close to comprehensive as I have come across, and he does a great job of making it understandable. What it means for us here is that this extension will add this `sorted` method to any type that conforms to `Sequence`. That means not only can we call it on an `Array`, we can also call it on a `Set`, a `Dictionary`, or even on a `String`(although I'm not sure how often that is useful).
```swift
let set = Set([wayne, derry, dan])
let alphabetical = set.sorted(by: \.name))
// alphabetical == [dan, derry, wayne]

let numberOfPuppers = [wayne: 6, derry: 4, dan: 9]
let byLeastDrunk = numberOfPuppers.sorted(by: \.value)
// byLeastDrunk == [(key: Derry, value: 4), (key: Wayne, value: 6), (key: Dan, value: 9)]

let sortedLetters = "Sushis and sashimis.".sorted(by: \.description)
// sortedLetters == [" ", " ", ".", "S", "a", "a", "d", "h", "h", "i", "i", "i", "m", "n", "s", "s", "s", "s", "s", "u"]
```

## Wrap Up ##
So there you have it. We've looked at how to use `sort/sorted` even though their signatures might be a little intimidating. We've looked at how to use them with as few characters of code as possible. And we've looked at how to sort objects that may not make sense to sort as a whole, but have properties you can sort on. I hope that gives you a better picture of how to use these methods. If you have any questions, tips, tricks or stories about sorting in Swift, be sure to share them in the comments.

-----

If this has been helpful [buy me a coffee!](https://www.buymeacoffee.com/dilloncodes)