Swift with Copilot: Sort list ascending and descending
Video: Swift with Copilot: Sort list ascending and descending by Taught by Celeste AI - AI Coding Coach
Swift with Copilot: Sort List Ascending and Descending
arr.sorted()ascending.arr.sorted(by: >)descending. Theby:parameter takes any(a, b) -> Bool—<,>, or your own custom comparator.
Same data, two orders. Swift makes both one-liners.
The Copilot prompt
// Sort numbers ascending and descending
let numbers = [5, 2, 8, 1, 9, 3]
Copilot completes:
let numbers = [5, 2, 8, 1, 9, 3]
let ascending = numbers.sorted()
let descending = numbers.sorted(by: >)
print("Asc: \(ascending)")
print("Desc: \(descending)")
// Asc: [1, 2, 3, 5, 8, 9]
// Desc: [9, 8, 5, 3, 2, 1]
Walkthrough
sorted(by: <closure>) takes a closure (a, b) -> Bool that answers "should a come before b?"
arr.sorted(by: <) // ascending
arr.sorted(by: >) // descending
Operators in Swift are functions. < and > work directly as the by: argument because they have type (Int, Int) -> Bool.
For a custom comparator, write a closure:
let absSorted = numbers.sorted { abs($0) < abs($1) }
// sort by absolute value
$0 and $1 are the two arguments. The closure returns true if $0 should come before $1.
Sort in place, descending
var numbers = [5, 2, 8, 1, 9, 3]
numbers.sort(by: >)
print(numbers)
// [9, 8, 5, 3, 2, 1]
Same by: form on the in-place version.
Reversed: another way to descending
let descending = numbers.sorted().reversed()
print(Array(descending))
// [9, 8, 5, 3, 2, 1]
reversed() returns a ReversedCollection — a lightweight view, not a new array. Use Array(...) to materialize. For one-pass iteration, no need.
sorted(by: >) is more direct than sorted().reversed().
Sort strings
let names = ["Charlie", "Alice", "Bob"]
let sorted = names.sorted()
// ["Alice", "Bob", "Charlie"]
Lexicographic, case-sensitive. For case-insensitive:
let sortedCI = names.sorted { $0.lowercased() < $1.lowercased() }
Sort objects by a property
struct Person {
let name: String
let age: Int
}
let people = [
Person(name: "Alice", age: 30),
Person(name: "Bob", age: 25),
Person(name: "Charlie", age: 35),
]
// By age
let byAge = people.sorted { $0.age < $1.age }
// By name
let byName = people.sorted { $0.name < $1.name }
// By age descending
let byAgeDesc = people.sorted { $0.age > $1.age }
For a more reusable pattern, conform to Comparable:
extension Person: Comparable {
static func < (lhs: Person, rhs: Person) -> Bool {
lhs.age < rhs.age
}
static func == (lhs: Person, rhs: Person) -> Bool {
lhs.age == rhs.age && lhs.name == rhs.name
}
}
people.sorted() // by age, no need for closure
Useful when the type has a "natural" order.
Multi-key sort (tiebreaker)
let byAgeThenName = people.sorted {
if $0.age != $1.age { return $0.age < $1.age }
return $0.name < $1.name
}
Or chain with tuples:
let sorted = people.sorted { ($0.age, $0.name) < ($1.age, $1.name) }
Tuples are Comparable if their elements are. Lexicographic compare: age first, name as tiebreaker.
KeyPath sorting (Swift 5.0+)
For one-key sorts, KeyPaths are cleaner:
let byAge = people.sorted(using: KeyPathComparator(\.age))
KeyPathComparator is from Foundation (iOS 15+, macOS 12+).
For older code, write an extension:
extension Sequence {
func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>) -> [Element] {
sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
}
}
let byAge = people.sorted(by: \.age)
let byName = people.sorted(by: \.name)
Now \.age (a KeyPath) replaces a closure. Compact and reusable.
Common stumbles
sorted(by: <) vs sorted(). Both ascending. sorted() works because the default uses <.
Forgetting to materialize reversed(). let r = arr.reversed() is a view, not Array. Array(r) to copy.
Sorting nils. [1, nil, 3].sorted() errors because Optional doesn't conform to Comparable directly. Filter or write a custom comparator.
Comparator returning wrong type. Must return Bool. sorted { $0 - $1 } errors — that's Int.
Not stable. If preserving relative order of equals matters, multi-key sort with a tiebreaker.
What's next
Episode 5: What day is today? Date, Calendar, DateFormatter.
Recap
sorted(by: <) ascending (= sorted()), sorted(by: >) descending. Pass any (a, b) -> Bool closure for custom orders. For object arrays, sort by closure on a property or conform to Comparable. Multi-key via tuple comparison. KeyPathComparator (newer SDKs) for keypath-based sorts.
Next episode: today's date.