Overview
These methods live on Sequence and Collection, so they work on Array, Set, Dictionary, String, and your own conforming types. Non-mutating names (sorted) pair with mutating ones (sort). Without .lazy, each step builds an intermediate array. Value semantics are covered in swift-protocols.
Transform
Use compactMap to drop nil and reduce(into:) to build collections.
| Method | Returns | Notes |
|---|---|---|
map { } | [T] | Same count. |
compactMap { } | [T] | Maps and drops nil. |
flatMap { } | [T] | Maps to sequences and flattens one level. |
filter { } | [Element] | Keeps elements where the closure is true. |
reduce(0) { } | Result | Fold; always give an initial value. |
reduce(into: [:]) { } | Result | Mutates the accumulator in place; no copy per step. |
let nums = [1, 2, 3, 4, 5]
nums.map { $0 * 2 } // [2, 4, 6, 8, 10]
nums.filter { $0.isMultiple(of: 2) } // [2, 4]
nums.reduce(0, +) // 15
["1", "x", "3"].compactMap { Int($0) } // [1, 3]
let freq = nums.reduce(into: [Int: Int]()) { $0[$1, default: 0] += 1 }Sort and order
Use sorted for a copy and sort for in-place.
| Method | Mutates | Notes |
|---|---|---|
sorted(), sorted(by:) | no | Needs Comparable or a closure. |
sort(), sort(by:) | yes | On mutable random-access collections such as Array. |
reversed() | no | O(1) ReversedCollection view; wrap in Array(...) for a copy. |
shuffled() | no | New random order. |
users.sorted { ($0.lastName, $0.firstName) < ($1.lastName, $1.firstName) } // tuple comparisonSearch
Use contains(where:) and first(where:) instead of filtering then indexing.
| Method | Returns |
|---|---|
contains(x), contains { } | Bool (contains(x) needs Equatable). |
first, last, first { }, last { } | Element? |
firstIndex(of:), firstIndex { } | Index? |
min(), max(), min(by:), max(by:) | Element? |
Iterate
Use for ... in when you need an early exit.
| Method | Notes |
|---|---|
forEach { } | Side effects; return only skips to the next element. |
enumerated() | (offset, element) pairs; offsets start at 0, they are not collection indices. |
zip(a, b) | Pairs elements; stops at the shorter sequence. |
joined(), joined(separator:) | Flatten sequences / join strings. |
Dictionary
Use mapValues and Dictionary(grouping:) instead of manual loops.
| Operation | Syntax |
|---|---|
| Filter | dict.filter { $0.value >= 80 } returns [K: V]. |
| Map values | dict.mapValues { $0 + 10 }, dict.compactMapValues { Int($0) } |
| Group | Dictionary(grouping: users, by: { $0.department }) returns [K: [V]]. |
| Merge | dict.merging(other) { _, new in new } resolves key conflicts. |
| Default read/write | dict[key, default: 0] += 1 |
Lazy
Put .lazy first to compute only the elements you consume.
let firstFive = (1...1_000_000).lazy
.map { $0 * $0 }
.filter { $0.isMultiple(of: 3) }
.prefix(5)
Array(firstFive)Gotchas
Avoid these; each copies data, hides a mismatch, or cannot exit early.
| Gotcha | Fix |
|---|---|
forEach cannot break or continue. | Use a for ... in loop. |
reduce with an array or dictionary accumulator copies it each step. | Use reduce(into:). |
reversed() is a view, not an Array. | Wrap it: Array(a.reversed()). |
zip hides length mismatches. | Assert equal counts first if they must match. |
Array.contains is O(n). | Convert to a Set before repeated membership checks. |
flatMap on optionals was renamed compactMap in Swift 4.1. | Use compactMap to drop nil. |