# Swift reduce, compactMap, and flatMap Explained Clearly

Source: https://devdocs10.com/articles/swift/swift-collection-reduce-compactmap-flatmap  
By Murat Bo · Published 2026-05-12 · DevDocs10 (https://devdocs10.com)

Swift collections include several powerful methods for transforming data, and three of the most useful are `reduce`, `compactMap`, and `flatMap`. They solve different problems: combining many values into one, transforming values while removing `nil`, and flattening nested collections. Understanding when to use each one helps you write shorter, clearer, and more reliable Swift code.

> **Quick answer:** Use `reduce` when you want one final result from many elements, such as a total or summary. Use `compactMap` when you want to transform values and discard `nil` results. Use `flatMap` when you want to flatten nested collections into a single collection.

> **Difficulty:** Beginner
>
> **Helpful to know first:** You'll understand this better if you already know basic Swift arrays, closures, and optionals.

## 1. What Are reduce, compactMap, and flatMap?

These three methods are collection operations in the Swift standard library, but they are not interchangeable. Each one has a distinct purpose.

- `reduce` combines all elements into one final value.
- `compactMap` transforms each element and removes any `nil` results.
- `flatMap` transforms each element into a sequence, then flattens the nested result by one level.
- All three are often used with arrays, but they work with many Swift sequence and collection types.
- They are commonly confused with `map`, which transforms elements but keeps the same number of results.

In practical terms, think of them like this:

- `reduce`: “Turn many values into one.”
- `compactMap`: “Convert values, but throw away failures.”
- `flatMap`: “Merge nested lists into one list.”

## 2. Why reduce, compactMap, and flatMap Matter

These methods matter because they let you express common data-processing tasks in a direct and readable way. Instead of writing manual loops, temporary variables, and repeated condition checks, you can describe the transformation you want more clearly.

Use them when you are working with data pipelines such as:

- Adding prices from a shopping cart
- Converting strings like `["1", "2", "x"]` into valid integers
- Flattening grouped data such as arrays of arrays
- Building dictionaries, strings, or summaries from many values

Do not use them just because they look concise. If a loop is clearer for a very complex operation, a loop may be the better choice. These methods are most useful when each step has one clear purpose.

## 3. Basic Syntax

### reduce syntax

`reduce` starts with an initial result and combines each element into that result.

```swift
let numbers = [1, 2, 3, 4]
let sum = numbers.reduce(0) { partialResult, number in
    partialResult + number
}
```

This starts at `0`, then adds each number in the array. The final value of `sum` is `10`.

### compactMap syntax

`compactMap` applies a transformation and keeps only non-`nil` results.

```swift
let texts = ["1", "2", "hello", "4"]
let values = texts.compactMap { Int($0) }
```

`Int($0)` returns an optional integer. Valid number strings become integers, and invalid values become `nil`. `compactMap` removes the `nil` values, so `values` becomes `[1, 2, 4]`.

### flatMap syntax

`flatMap` is commonly used when each element produces another sequence, creating nested results that should be flattened.

```swift
let groups = [[1, 2], [3, 4], [5]]
let allNumbers = groups.flatMap { $0 }
```

The result is a single flat array: `[1, 2, 3, 4, 5]`.

> A common source of confusion is older Swift code that used `flatMap` for optionals. In modern Swift, use `compactMap` to remove `nil` values from collections.

## 4. Step-by-Step Examples

### Example 1: Using reduce to calculate a total price

Suppose you have item prices and want one final total. This is a classic `reduce` task because many values become one value.

```swift
let prices = [19.99, 5.50, 12.00]
let total = prices.reduce(0.0) { runningTotal, price in
    runningTotal + price
}

print(total)
```

Output (tested with Swift 6.4):

```text
37.489999999999995
```

This produces one final number containing the sum of all prices.

### Example 2: Using compactMap to parse valid integers

When data comes from user input, a file, or an API, some values may not convert cleanly. `compactMap` lets you keep only valid converted values.

```swift
let rawScores = ["100", "95", "absent", "88"]
let scores = rawScores.compactMap { Int($0) }

print(scores)
```

Output (tested with Swift 6.4):

```text
[100, 95, 88]
```

The result is `[100, 95, 88]`. The invalid string `"absent"` becomes `nil` and is removed.

### Example 3: Using flatMap to flatten nested arrays

Sometimes your data is already grouped into subarrays, but your next step needs one flat list.

```swift
let weeklySteps = [[3000, 5000], [4500], [8000, 7000]]
let allSteps = weeklySteps.flatMap { $0 }

print(allSteps)
```

Output (tested with Swift 6.4):

```text
[3000, 5000, 4500, 8000, 7000]
```

This returns one array with all values in order.

### Example 4: Combining compactMap and reduce

These methods often work well together. Here, invalid price strings are removed first, then valid prices are summed.

```swift
let rawPrices = ["10.5", "invalid", "25.0", "4.5"]

let grandTotal = rawPrices
    .compactMap { Double($0) }
    .reduce(0.0) { sum, price in
        sum + price
    }

print(grandTotal)
```

Output (tested with Swift 6.4):

```text
40.0
```

This is a realistic pattern in Swift: clean the data, then aggregate it.

### Example 5: map vs compactMap vs flatMap

These three are often mixed up, so it helps to see them side by side.

```swift
let values = ["1", "x", "3"]

let mapped = values.map { Int($0) }
let compacted = values.compactMap { Int($0) }

let nested = [[1, 2], [3]]
let flattened = nested.flatMap { $0 }
```

Here, `mapped` is `[Optional(1), nil, Optional(3)]`, `compacted` is `[1, 3]`, and `flattened` is `[1, 2, 3]`.

## 5. Practical Use Cases

- Use `reduce` to total cart prices, count characters, build grouped summaries, or combine values into a dictionary.
- Use `compactMap` to parse user input, filter invalid API fields, or load only valid IDs from text data.
- Use `flatMap` to flatten nested arrays such as sections of items, batches of records, or grouped tags.
- Use `compactMap` followed by `reduce` when some source values may fail conversion but the remaining valid values should still be processed.
- Use `reduce` when you need one final summary object rather than another array.

## 6. Common Mistakes

### Mistake 1: Using map when compactMap is needed

Beginners often use `map` to convert strings into numbers and then wonder why the result contains optionals.

**Problem:** `map` preserves the number of elements, so failed conversions stay in the result as `nil`. This can lead to optional-handling errors later.

```swift
let texts = ["1", "hello", "3"]
let numbers = texts.map { Int($0) }
```

**Fix:** Use `compactMap` when you want to discard failed conversions.

```swift
let texts = ["1", "hello", "3"]
let numbers = texts.compactMap { Int($0) }
```

The corrected version works because `compactMap` removes the `nil` values and returns a clean `[Int]`.

### Mistake 2: Using the wrong initial value with reduce

The initial value in `reduce` affects both the result type and the final answer.

**Problem:** Starting with the wrong value can produce an incorrect result or an unexpected type, especially when building strings, arrays, or dictionaries.

```swift
let numbers = [1, 2, 3]
let sum = numbers.reduce(10) { result, number in
    result + number
}
```

**Fix:** Choose the true starting value for the operation. For addition, that is usually `0`.

```swift
let numbers = [1, 2, 3]
let sum = numbers.reduce(0) { result, number in
    result + number
}
```

The corrected version works because the accumulator starts from the correct neutral value.

### Mistake 3: Expecting flatMap to remove nil values from a collection

Older Swift examples sometimes show `flatMap` being used for optional removal, which confuses many learners.

**Problem:** In modern Swift, using `flatMap` for this purpose is the wrong tool and can lead to confusing type errors or outdated code patterns.

```swift
let texts = ["1", "x", "3"]
let numbers = texts.flatMap { Int($0) }
```

**Fix:** Use `compactMap` when the transformation returns an optional and you want only successful results.

```swift
let texts = ["1", "x", "3"]
let numbers = texts.compactMap { Int($0) }
```

The corrected version works because `compactMap` is the modern and intended API for removing `nil` results from collection transformations.

### Mistake 4: Returning the wrong shape from flatMap

`flatMap` is for flattening one level of nested sequences. If the closure does not return a sequence, it is usually the wrong method.

**Problem:** When the closure returns a single value instead of a nested collection, the code may fail to compile or express the wrong intention.

```swift
let numbers = [1, 2, 3]
let doubled = numbers.flatMap { $0 * 2 }
```

**Fix:** Use `map` when you are transforming each element into one new element.

```swift
let numbers = [1, 2, 3]
let doubled = numbers.map { $0 * 2 }
```

The corrected version works because `map` is designed for one-to-one element transformation.

## 7. Best Practices

### Practice 1: Choose the method based on the result shape

A simple way to choose correctly is to ask what kind of result you want at the end.

```swift
// Many values become one value
let sum = [1, 2, 3].reduce(0, +)

// Values convert, invalid ones are removed
let ints = ["1", "x", "3"].compactMap { Int($0) }

// Nested arrays become one flat array
let merged = [[1], [2, 3]].flatMap { $0 }
```

This works well because the method matches the intended output shape instead of just the input type.

### Practice 2: Prefer clear closure names when the operation is not obvious

Shorthand syntax like `$0` is fine for small expressions, but named parameters are often easier to read in longer closures.

```swift
let prices = ["9.99", "oops", "14.50"]

let total = prices
    .compactMap { priceText in
        Double(priceText)
    }
    .reduce(0.0) { runningTotal, price in
        runningTotal + price
    }
```

This is easier to maintain because each closure argument explains its role.

### Practice 3: Keep reduce focused on accumulation

`reduce` is best when each step updates one accumulated result. If the closure becomes hard to read, consider a loop or a different method.

```swift
let words = ["Swift", "is", "fun"]
let sentence = words.reduce("") { result, word in
    result.isEmpty ? word : result + " " + word
}
```

This is a reasonable use of `reduce` because the result remains one growing string.

## 8. Limitations and Edge Cases

- `flatMap` flattens only one level. If your data is nested more deeply, you may need repeated flattening or a custom solution.
- `compactMap` removes `nil` results, which means you lose information about which original elements failed conversion.
- `reduce` can become hard to read if the accumulator logic is too complex.
- If you see code online using `flatMap` to remove `nil` values from a collection, it may be written for older Swift versions.
- A common “not working” scenario is choosing `flatMap` when `map` or `compactMap` is actually needed. The clue is the closure result: one value, optional value, or sequence.
- You may encounter compiler messages such as `Cannot convert value of type` when the closure return type does not match what the method expects.

## 9. Practical Mini Project

In this mini project, you will process order data stored as nested arrays of price strings. The goal is to flatten the batches, convert valid prices, and compute a final total.

```swift
let orderBatches = [
    ["12.50", "9.99", "invalid"],
    ["5.00", "7.25"],
    ["error", "14.75"]
]

let allPrices = orderBatches.flatMap { $0 }
let validPrices = allPrices.compactMap { Double($0) }
let totalRevenue = validPrices.reduce(0.0) { sum, price in
    sum + price
}

print("All prices: \(allPrices)")
print("Valid prices: \(validPrices)")
print("Total revenue: \(totalRevenue)")
```

Output (tested with Swift 6.4):

```text
All prices: ["12.50", "9.99", "invalid", "5.00", "7.25", "error", "14.75"]
Valid prices: [12.5, 9.99, 5.0, 7.25, 14.75]
Total revenue: 49.49
```

This example shows the three methods working together in a realistic sequence. `flatMap` removes one level of nesting, `compactMap` filters out invalid values during conversion, and `reduce` creates the final total.

## 10. Key Points

- `reduce` combines a collection into one final value.
- `compactMap` transforms elements and removes `nil` results.
- `flatMap` flattens one level of nested sequences.
- `map` is different because it transforms elements without removing failures or flattening nesting.
- The best method depends on the shape of the result you want.
- Modern Swift uses `compactMap`, not `flatMap`, for optional-removal in collections.

## 11. Practice Exercise

Try this exercise to confirm that you can tell these methods apart.

- Start with a nested array of score strings.
- Flatten the nested array into one array.
- Convert valid score strings to integers.
- Calculate the total score.

**Expected output:** a flat array of strings, an array of valid integers, and a final total.

**Hint:** Use `flatMap` first, then `compactMap`, then `reduce`.

```swift
let scoreGroups = [
    ["10", "20"],
    ["x", "15"],
    ["25"]
]

let flatScores = scoreGroups.flatMap { $0 }
let validScores = flatScores.compactMap { Int($0) }
let total = validScores.reduce(0) { sum, score in
    sum + score
}

print("Flat scores: \(flatScores)")
print("Valid scores: \(validScores)")
print("Total: \(total)")
```

Output (tested with Swift 6.4):

```text
Flat scores: ["10", "20", "x", "15", "25"]
Valid scores: [10, 20, 15, 25]
Total: 70
```

## 12. Final Summary

`reduce`, `compactMap`, and `flatMap` are all transformation tools, but each solves a different problem. `reduce` creates one result from many elements, `compactMap` keeps only successful transformed values, and `flatMap` flattens nested sequences by one level. Once you recognize the output shape you need, choosing the right method becomes much easier.

As you continue learning Swift collections, compare these methods with `map`, `filter`, and `sorted`. Those methods, together with the three covered here, form a core set of tools for writing expressive and maintainable collection code.
