# Swift map, filter, and sorted: Transforming Collections

Source: https://devdocs10.com/articles/swift/swift-collection-map-filter-sorted  
By Murat Bo · Published 2026-05-12 · DevDocs10 (https://devdocs10.com)

Swift collections often need to be transformed before you can display, store, or process their data. The three most common tools for that job are `map`, `filter`, and `sorted`. In this article, you will learn what each method does, how their closures work, when to use one instead of another, and how to avoid the mistakes beginners often make.

> **Quick answer:** Use `map` to convert every element into a new value, `filter` to keep only elements that match a condition, and `sorted` to return a new collection ordered by a comparison rule. All three return new collections instead of changing the original one.

> **Difficulty:** Beginner
>
> **Helpful to know first:** You will understand this better if you already know basic Swift syntax, arrays, closures, and simple types like `String`, `Int`, and `Bool`.

## 1. What Is map, filter, and sorted?

`map`, `filter`, and `sorted` are standard library methods used to create new collections from existing ones.

- `map` transforms each element into a new value.
- `filter` keeps only elements that pass a test.
- `sorted` returns elements in a chosen order.
- They are commonly used with arrays, but they also work with many other Swift collection types.
- They do not usually mutate the original collection, which makes code easier to reason about.

These methods solve a common problem: taking a list of values and producing a cleaner, more useful version of that list without writing a manual loop every time.

They are also naturally compared with each other because they answer different questions:

- `map`: “How should each value change?”
- `filter`: “Which values should stay?”
- `sorted`: “In what order should the values appear?”

## 2. Why map, filter, and sorted Matters

These methods matter because collection processing is everywhere in Swift programs. You might fetch data from an API, load user input, read a file, or build a menu for display. In each case, the raw data is often not in the exact form you need.

Instead of writing long loops with temporary variables, you can express your intent directly:

- Convert product prices from integers to formatted strings with `map`.
- Keep only active users with `filter`.
- Display names alphabetically with `sorted`.

This style has practical benefits:

- Code is shorter and easier to read.
- The purpose of the code is clearer at a glance.
- You reduce the chance of loop-related bugs, such as forgetting to append or update a value.
- Chaining transformations can produce very expressive code.

That said, these methods are not always the best choice. If you need complex stateful logic, early exits, or performance-sensitive mutation of the same array, a loop may sometimes be clearer.

## 3. Basic Syntax

Each of these methods takes a closure. The closure explains how to transform, test, or compare elements.

### Using map

This example converts numbers into strings.

```swift
let numbers = [1, 2, 3]
let labels = numbers.map { number in
    "Item \(number)"
}
```

Here, the closure runs once for every element. For each `number`, it returns a new string, so the result is an array of strings.

### Using filter

This example keeps only even numbers.

```swift
let numbers = [1, 2, 3, 4, 5]
let evenNumbers = numbers.filter { number in
    number % 2 == 0
}
```

The closure must return `true` or `false`. Elements that return `true` stay in the new array.

### Using sorted

This example sorts numbers from smallest to largest.

```swift
let numbers = [5, 2, 8, 1]
let sortedNumbers = numbers.sorted()
```

For values that already know how to compare themselves, such as `Int` and `String`, you can call `sorted()` with no closure.

For custom ordering, pass a closure:

```swift
let names = ["Mia", "Alex", "Charlotte"]
let byLength = names.sorted { first, second in
    first.count < second.count
}
```

The comparison closure for `sorted` receives two values and must return whether the first should come before the second.

## 4. Step-by-Step Examples

### Example 1: Convert temperatures with map

Suppose you have temperatures in Celsius and want a new array in Fahrenheit.

```swift
let celsiusValues = [0.0, 20.0, 30.0]
let fahrenheitValues = celsiusValues.map { celsius in
    (celsius * 9 / 5) + 32
}
```

This creates a new array where each original value has been transformed. The original `celsiusValues` array stays unchanged.

### Example 2: Keep passing scores with filter

Now imagine a list of exam scores where only passing values should remain.

```swift
let scores = [45, 88, 62, 30, 91]
let passingScores = scores.filter { score in
    score >= 50
}
```

The closure checks each score and keeps only the ones that meet the condition. This is more direct than writing a loop and appending values manually.

### Example 3: Sort names alphabetically with sorted

Sorting strings is one of the most common uses of `sorted`.

```swift
let names = ["Zoe", "Adam", "Lina"]
let alphabeticalNames = names.sorted()
```

The result is a new array ordered alphabetically. This is the simplest form because `String` already supports standard comparison.

### Example 4: Sort products by price

For custom types, you usually provide a comparison closure.

```swift
struct Product {
    let name: String
    let price: Double
}

let products = [
    Product(name: "Keyboard", price: 99.0),
    Product(name: "Mouse", price: 49.0),
    Product(name: "Monitor", price: 199.0)
]

let cheapestFirst = products.sorted { first, second in
    first.price < second.price
}
```

This sorts the product array by the `price` property. The comparison closure makes the sorting rule explicit.

### Example 5: Chain map, filter, and sorted together

These methods become especially powerful when combined.

```swift
let numbers = [8, 3, 12, 5, 10]

let result = numbers
    .filter { $0 >= 5 }
    .map { $0 * 2 }
    .sorted()
```

This code first keeps values greater than or equal to 5, then doubles each remaining value, then sorts the final result. Chaining works well when each step has one clear purpose.

## 5. Practical Use Cases

- Convert arrays of model data into display strings using `map`.
- Remove invalid or empty user input values with `filter`.
- Order products, tasks, or messages by date, price, or priority with `sorted`.
- Create a cleaned and ordered report by chaining all three methods together.
- Prepare API response data for UI display without manually looping through every item.
- Build search results by filtering matching items and sorting them by relevance or name.

## 6. Common Mistakes

### Mistake 1: Using map when you really need filter

Beginners sometimes try to use `map` to remove values. But `map` transforms every element and does not decide whether an element should stay or disappear.

**Problem:** This code creates an array of booleans instead of keeping only even numbers, because `map` transforms each element into the result of the condition.

```swift
let numbers = [1, 2, 3, 4]
let evens = numbers.map { $0 % 2 == 0 }
```

**Fix:** Use `filter` when the closure returns a condition that decides whether to keep an element.

```swift
let numbers = [1, 2, 3, 4]
let evens = numbers.filter { $0 % 2 == 0 }
```

The corrected version works because `filter` keeps only the elements for which the closure returns `true`.

### Mistake 2: Assuming sorted changes the original array

`sorted` returns a new array. It does not rearrange the original collection in place.

**Problem:** This code calls `sorted()` and then ignores the returned array, so the original array stays in the same order.

```swift
var scores = [30, 10, 20]
scores.sorted()
print(scores)
```

Output (tested with Swift 6.4):

```text
[30, 10, 20]
```

**Fix:** Assign the result back, or use `sort()` if you intentionally want to mutate the array in place.

```swift
var scores = [30, 10, 20]
scores = scores.sorted()
print(scores)
```

Output (tested with Swift 6.4):

```text
[10, 20, 30]
```

The corrected version works because the new sorted array is stored and used.

### Mistake 3: Returning the wrong type from a closure

Each method expects a different closure result. `map` can return any transformed value, `filter` must return a Boolean, and `sorted` must return a Boolean comparison between two values.

**Problem:** This code returns an `Int` from a `filter` closure, which causes a compile-time type mismatch.

```swift
let numbers = [1, 2, 3]
let result = numbers.filter { number in
    number * 2
}
```

**Fix:** Return a Boolean condition from `filter`, such as whether the number is greater than a threshold.

```swift
let numbers = [1, 2, 3]
let result = numbers.filter { number in
    number > 1
}
```

The corrected version works because `filter` receives the true-or-false test it requires.

### Mistake 4: Confusing sorted() with sort()

This is a very common Swift confusion. The names are similar, but their behavior is different.

**Problem:** This code tries to call the mutating `sort()` method on a constant array, which produces an error because the array cannot be modified.

```swift
let names = ["Sam", "Ava", "Ben"]
names.sort()
```

**Fix:** Use `sorted()` when you want a new array, or declare the array with `var` if you truly need in-place sorting.

```swift
let names = ["Sam", "Ava", "Ben"]
let sortedNames = names.sorted()
```

The corrected version works because `sorted()` does not require the original array to be mutable.

## 7. Best Practices

### Practice 1: Pick the method that matches your intent

When someone reads your code, they should understand immediately whether you are transforming, filtering, or ordering data. Using the correct method makes that intent obvious.

Less clear:

```swift
var result: [Int] = []
for number in [1, 2, 3] {
    result.append(number * 2)
}
```

Preferred:

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

The preferred version is shorter and clearly communicates that every element is being transformed.

### Practice 2: Keep each closure focused on one simple idea

Closures are easiest to read when they do one thing. If the logic becomes too long, split it into multiple steps or a named function.

Less preferred:

```swift
let values = [3, 7, 2, 9]
let result = values.filter { number in
    if number > 5 {
        return true
    } else {
        return false
    }
}
```

Preferred:

```swift
let values = [3, 7, 2, 9]
let result = values.filter { $0 > 5 }
```

The preferred version is easier to scan and reduces unnecessary noise.

### Practice 3: Use chained transformations carefully

Chaining is powerful, but too many steps in one expression can become hard to debug. Keep chains readable and line-break them when needed.

Less preferred:

```swift
let finalValues = [12, 5, 18, 3].filter { $0 > 4 }.map { $0 * 10 }.sorted()
```

Preferred:

```swift
let finalValues = [12, 5, 18, 3]
    .filter { $0 > 4 }
    .map { $0 * 10 }
    .sorted()
```

The preferred version keeps the transformation pipeline clear and easier to maintain.

## 8. Limitations and Edge Cases

- `map` does not remove elements. If you need to skip values entirely, use `filter` or consider `compactMap` when working with optionals.
- `filter` keeps the original element type. It does not transform values into a different type.
- `sorted()` without a closure works only when the element type supports comparison, such as `Int` or `String`.
- Sorting custom types usually requires a closure like `{ $0.price < $1.price }`.
- `sorted` returns a new array, even when the original collection is another type. That can matter if you expected in-place mutation.
- If you chain many transformations on very large collections, readability and performance may both deserve closer attention.
- A common “not working” case is trying to sort a custom struct without telling Swift how two values should be compared.

> A related method you will often see is `compactMap`. It transforms elements like `map`, but also removes `nil` results. That is useful when converting strings to numbers, for example.

## 9. Practical Mini Project

Let’s build a small example that processes student scores. We will filter out failing scores, convert the remaining scores into label strings, and sort them from highest to lowest.

```swift
let scores = [72, 48, 91, 63, 55]

let report = scores
    .filter { $0 >= 50 }
    .sorted { $0 > $1 }
    .map { "Passed with score: \($0)" }

for line in report {
    print(line)
}
```

Output (tested with Swift 6.4):

```text
Passed with score: 91
Passed with score: 72
Passed with score: 63
Passed with score: 55
```

This mini project shows all three methods working together:

- `filter` removes failing scores.
- `sorted` orders the passing scores from highest to lowest.
- `map` converts the numbers into readable output strings.

The result is a clean processing pipeline that reads almost like a description of the task itself.

## 10. Key Points

- `map` transforms every element into a new value.
- `filter` keeps only elements that match a Boolean condition.
- `sorted` returns a new array in sorted order.
- `sorted()` does not mutate the original collection; `sort()` does.
- The closure type matters: transform for `map`, test for `filter`, compare for `sorted`.
- These methods can be chained to create clear, expressive collection-processing code.

## 11. Practice Exercise

Try this exercise to confirm you understand how the three methods differ.

- Start with an array of names: `["Olivia", "Max", "Sophia", "Leo"]`.
- Use `filter` to keep only names with more than 3 characters.
- Use `sorted` to arrange the remaining names alphabetically.
- Use `map` to convert each name into a greeting like `"Hello, Olivia!"`.

**Expected output:** An array containing greeting strings for the filtered and sorted names.

**Hint:** Think about the order of operations. It is usually easier to filter first, sort second, and transform last.

```swift
let names = ["Olivia", "Max", "Sophia", "Leo"]

let greetings = names
    .filter { $0.count > 3 }
    .sorted()
    .map { "Hello, \($0)!" }

print(greetings)
```

Output (tested with Swift 6.4):

```text
["Hello, Olivia!", "Hello, Sophia!"]
```

## 12. Final Summary

`map`, `filter`, and `sorted` are some of the most useful collection methods in Swift. They let you transform data, remove unwanted elements, and control ordering with concise, readable code. Once you understand the purpose of each method, many common loops become much simpler to write and easier to understand.

The most important habit is choosing the right tool for the job: `map` changes values, `filter` selects values, and `sorted` orders values. After you are comfortable with these, a strong next step is learning related methods such as `compactMap`, `reduce`, and `forEach` so you can handle even more collection-processing tasks in Swift.
