---
title: "Swift Collection Methods Cheatsheet"
slug: "swift-collection-methods"
category: "cheatsheets"
tags: ["cheatsheets", "swift", "collections", "functional", "ios", "reference"]
status: "stable"
last_updated: 2026-05-14
summary: "Swift map, filter, reduce, sorted, forEach, zip, and enumerated on Array, Set, and Dictionary with return types and lazy evaluation."
related:
  [
    "[[coding/swift]]",
    "[[coding/swift-value-types]]",
    "[[coding/swift-protocols]]",
    "[[ios/swiftui]]",
    "[[coding/swift-async-await]]",
    "[[coding/swift-optionals]]",
    "[[cheatsheets/index|Cheatsheets]]",
  ]
---

## Overview

Swift collection methods live on the `Sequence` and `Collection` protocols, so they work on `Array`, `Set`, `Dictionary`, `String`, and any custom type that conforms. All methods in the standard library are non-mutating by default; mutating variants typically carry a different name (`sort()` mutates, `sorted()` does not). Chaining methods produces lazy sequences only when you call `.lazy` first; otherwise each transformation creates an intermediate array. For value semantics and copy-on-write behavior, see [[coding/swift-value-types]].

## Transformation methods

Non-mutating; return a new collection.

| Method            | Input                         | Returns     | Notes                                                      |
| ----------------- | ----------------------------- | ----------- | ---------------------------------------------------------- |
| `map(_:)`         | `(Element) -> T`              | `[T]`       | Transform every element; always same count.                |
| `compactMap(_:)`  | `(Element) -> T?`             | `[T]`       | Map and drop `nil` results; flattens optionals.            |
| `flatMap(_:)`     | `(Element) -> Sequence`       | `[T]`       | Map and flatten one level; equivalent to `map().joined()`. |
| `filter(_:)`      | `(Element) -> Bool`           | `[Element]` | Keep elements where closure returns `true`.                |
| `reduce(_:_:)`    | `(Result, Element) -> Result` | `Result`    | Fold to a single value; always provide an initial value.   |
| `reduce(into:_:)` | `(inout Result, Element)`     | `Result`    | More efficient for appending to containers; avoids copies. |

```swift
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

let strings = ["1", "two", "3", "four"]
strings.compactMap { Int($0) }    // [1, 3]

let nested = [[1, 2], [3, 4]]
nested.flatMap { $0 }             // [1, 2, 3, 4]

// reduce(into:) for building a dictionary
let freq = nums.reduce(into: [:]) { dict, n in dict[n, default: 0] += 1 }
```

## Sorting and ordering

| Method        | Mutates | Returns              | Notes                                                            |
| ------------- | ------- | -------------------- | ---------------------------------------------------------------- |
| `sorted()`    | No      | `[Element]`          | Ascending order; requires `Comparable`.                          |
| `sorted(by:)` | No      | `[Element]`          | Custom comparator.                                               |
| `sort()`      | Yes     | `Void`               | In-place; `Array` only.                                          |
| `sort(by:)`   | Yes     | `Void`               | In-place with comparator.                                        |
| `reversed()`  | No      | `ReversedCollection` | O(1) lazy view; use `Array(arr.reversed())` for a concrete copy. |
| `shuffled()`  | No      | `[Element]`          | Returns a new randomly ordered array.                            |

```swift
let words = ["banana", "apple", "cherry"]
words.sorted()                          // ["apple", "banana", "cherry"]
words.sorted { $0.count < $1.count }    // ["apple", "banana", "cherry"]

// Sort by multiple criteria
users.sorted {
    $0.lastName == $1.lastName
        ? $0.firstName < $1.firstName
        : $0.lastName < $1.lastName
}
```

## Search and existence

| Method                  | Returns    | Notes                                            |
| ----------------------- | ---------- | ------------------------------------------------ |
| `contains(_:)`          | `Bool`     | Requires `Equatable`; linear scan.               |
| `contains(where:)`      | `Bool`     | Predicate-based; short-circuits.                 |
| `first`                 | `Element?` | First element; `nil` for empty.                  |
| `first(where:)`         | `Element?` | First matching element or `nil`.                 |
| `last`                  | `Element?` | Last element; `nil` for empty.                   |
| `last(where:)`          | `Element?` | Last matching element or `nil`.                  |
| `firstIndex(of:)`       | `Index?`   | Index of first occurrence; requires `Equatable`. |
| `firstIndex(where:)`    | `Index?`   | Index of first predicate match.                  |
| `min()` / `max()`       | `Element?` | Minimum/maximum; requires `Comparable`.          |
| `min(by:)` / `max(by:)` | `Element?` | Custom comparator.                               |

```swift
let users = [User(name: "Alice", age: 30), User(name: "Bob", age: 25)]

users.contains { $0.age > 28 }          // true
users.first { $0.name == "Bob" }        // Optional(Bob)
users.max(by: { $0.age < $1.age })      // Optional(Alice)
users.firstIndex { $0.name == "Alice" } // Optional(0)
```

## Iteration and enumeration

| Method               | Returns              | Notes                                                               |
| -------------------- | -------------------- | ------------------------------------------------------------------- |
| `forEach(_:)`        | `Void`               | Iterate for side effects; cannot `break` or `return` from the loop. |
| `enumerated()`       | `EnumeratedSequence` | `(offset, element)` pairs; use in `for...in`.                       |
| `zip(_:_:)`          | `Zip2Sequence`       | Pair elements from two sequences; stops at the shorter.             |
| `joined()`           | `FlattenSequence`    | Flatten a sequence of sequences; no closure needed.                 |
| `joined(separator:)` | `String`             | Concatenate string elements with a separator.                       |

```swift
for (i, user) in users.enumerated() {
    print("\(i): \(user.name)")
}

let a = [1, 2, 3]
let b = ["one", "two", "three"]
for (n, s) in zip(a, b) {
    print(n, s)
}
// 1 one, 2 two, 3 three

["Hello", "world"].joined(separator: " ") // "Hello world"
```

## Dictionary-specific methods

`Dictionary` conforms to `Sequence` over `(key, value)` pairs.

| Operation              | Syntax                                  | Notes                                  |
| ---------------------- | --------------------------------------- | -------------------------------------- |
| Filter by key or value | `dict.filter { $0.key.hasPrefix("a") }` | Returns `[K: V]`.                      |
| Map values only        | `dict.mapValues { $0 * 2 }`             | Preserves keys; returns `[K: V]`.      |
| Compact-map values     | `dict.compactMapValues { Int($0) }`     | Drops `nil` values.                    |
| Group by key           | `Dictionary(grouping: arr) { $0.key }`  | Returns `[K: [V]]`.                    |
| Merge                  | `dict.merging(other) { _, new in new }` | Second closure resolves key conflicts. |

```swift
let scores = ["Alice": 90, "Bob": 72, "Carol": 88]

scores.filter { $0.value >= 80 }         // ["Alice": 90, "Carol": 88]
scores.mapValues { $0 + 10 }             // ["Alice": 100, "Bob": 82, "Carol": 98]

let grouped = Dictionary(grouping: users, by: { $0.department })
```

## Lazy evaluation

Prefix a chain with `.lazy` to avoid intermediate arrays.

```swift
// Without lazy: creates three intermediate arrays
let result = (1...1_000_000)
    .map { $0 * $0 }
    .filter { $0.isMultiple(of: 3) }
    .prefix(5)

// With lazy: no intermediate arrays; elements computed on demand
let lazyResult = (1...1_000_000).lazy
    .map { $0 * $0 }
    .filter { $0.isMultiple(of: 3) }
    .prefix(5)

Array(lazyResult) // materialize when needed
```

Use `.lazy` when the sequence is large and you only consume a small prefix, or when combining many transformations.

## Common gotchas

- `forEach` cannot `break` out of iteration. Use a `for...in` loop when early exit is needed.
- `flatMap` on a collection of optionals was renamed to `compactMap` in Swift 4.1. `flatMap` on a collection of sequences still flattens one level.
- `reduce` with a mutable container argument copies the accumulator on each step. Use `reduce(into:)` for `Array`, `Dictionary`, and `Set` accumulators; it passes the accumulator `inout`.
- `reversed()` returns a lazy `ReversedCollection` view, not a new `Array`. Passing it to a function expecting `[Element]` requires `Array(collection.reversed())`.
- `zip` stops at the shorter sequence without error. If you expect equal lengths, assert before zipping to catch mismatches.
- `sorted()` on a large array is O(n log n). For repeated lookups, consider a sorted data structure instead of re-sorting.
- `Set` has `contains` in O(1). `Array.contains` is O(n). Convert to `Set` before repeated membership tests.

## Related

- [[coding/swift]]
- [[coding/swift-value-types]]
- [[coding/swift-protocols]]
- [[ios/swiftui]]
- [[coding/swift-async-await]]
- [[coding/swift-optionals]]
- [[cheatsheets/index|Cheatsheets]]
