Start learning free

LESSON 100 OF 349 · ARRAYS I

Closures and sorting in Swift in Swift

Lesson

A closure is a function without a name that you write inline and hand to another function. Nowhere is this more useful than sorting: sorted(by:) doesn't guess how you want things ordered — it asks you. You pass a closure that receives two elements and returns true when the first one should come before the second:

let nums = [3, 1, 2]
let small = nums.sorted(by: { (a: Int, b: Int) -> Bool in
    return a < b
})
// small is [1, 2, 3]

That works, but Swift lets you shrink it dramatically. The compiler already knows the closure's types, single-expression closures return implicitly, and $0, $1 are automatic names for the first and second parameter:

let small = nums.sorted(by: { $0 < $1 })

And when the closure is the last argument, you can drop it out of the parentheses entirely — trailing closure syntax:

let big = nums.sorted { $0 > $1 }   // [3, 2, 1]

The closure doesn't have to compare the elements themselves — any rule works. { $0.count > $1.count } orders strings by their length, longest first.


The trap: sort() is not sorted()

Swift has two sorting methods and beginners mix them up constantly. sorted() returns a NEW array and leaves the original alone. sort() rearranges the array in place — so it needs a var. Call it on a let constant:

let names = ["Charlie", "Al"]
names.sort()

...and the compiler stops you cold:

trap.swift:2:7: error: cannot use mutating member on immutable value: 'names' is a 'let' constant
1 | let names = ["Charlie", "Al"]
  | `- note: change 'let' to 'var' to make it mutable
2 | names.sort()
  |       `- error: cannot use mutating member on immutable value: 'names' is a 'let' constant

"Mutating member" means the method modifies the thing it's called on. When you see this error, either switch to sorted() (usually what you want) or declare the array with var.


Assignment
Follow the Coding Tutorial: create let names = ["Bo", "Alexandra", "Kim", "Charlie"], then

  • sort it alphabetically into ascending using the full form sorted(by: { $0 < $1 }) and print it,
  • sort it by length, longest first, into byLength using trailing closure syntax sorted { $0.count > $1.count } and print it.

The exact expected output is:

ascending = ["Alexandra", "Bo", "Charlie", "Kim"]
byLength = ["Alexandra", "Charlie", "Kim", "Bo"]

Hint
sorted never changes names, so both sorts start from the same original array — and printing an array with \(...) shows it in brackets, exactly like the expected output.


STEP 1 OF 5
    Ctrl + Enter to check

    Closures And Sorting in Swift

    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free