Swift’s compactMap is a versatile and powerful method that combines mapping and filtering operations. It’s an essential tool for any Swift developer, allowing you to transform and clean up collections efficiently. In this post, we’ll explore compactMap through five practical examples, demonstrating its flexibility and utility in various scenarios.
What is compactMap?
According to Apple’s official Swift documentation, compactMap is defined as: “Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.”
This concise definition encapsulates the two main functions of compactMap:
- It applies a transformation to each element of a sequence.
- It filters out any nil results from that transformation.
Now, let’s dive into some examples to see compactMap in action.
Example 1: Filtering Optional Values
let possibleNumbers = ["1", "2", "three", "///4///", "5"]
let mapped: [Int?] = possibleNumbers.map { str in
Int(str)
}
// [1, 2, nil, nil, 5]
let compactMapped: [Int] = possibleNumbers.compactMap { str in
Int(str)
}
// [1, 2, 5]
In this example, we start with an array of strings, some of which can be converted to integers. Using map, we get an array of optional integers, including nil values. With compactMap, we get only the successfully converted integers, automatically removing the nil results.
Example 2: Transforming and Filtering Custom Types
struct Book {
let title: String
let pageCount: Int?
}
let library = [
Book(title: "Swift Programming", pageCount: 300),
Book(title: "iOS Development", pageCount: nil),
Book(title: "Algorithms", pageCount: 500)
]
let pageCountsOverThreshold = library.compactMap { book in
guard let pages = book.pageCount, pages > 400 else { return nil }
return pages
}
// [500]
In this example, we use compactMap to both transform Book objects into their page counts and filter for books with more than 400 pages. The result is an array containing only the page counts that meet our criteria.
Example 3: Working with Optionals in Dictionaries
let dict = ["a": 1, "b": 2, "c": nil, "d": 4]
let values = dict.compactMap { $0.value }
// [1, 2, 4]
When working with dictionaries that may contain nil values, compactMap is particularly useful. It allows us to extract all non-nil values in a single, elegant operation.
Example 4: Chaining compactMap with Other Methods
let mixedData = ["1", "fish", "2", "3", "dog", "4"]
let sumOfEvenNumbers = mixedData.compactMap { Int($0) }
.filter { $0 % 2 == 0 }
.reduce(0, +)
// 6
This final example demonstrates how compactMap can be chained with other collection methods. We start by converting strings to integers and removing non-numeric values, then filter for even numbers, and finally sum them up.
Remember, while compactMap is highly versatile, it’s important to use it judiciously. In some cases, separate map and filter operations might be more appropriate for clarity or performance reasons.
For more information on compactMap and other Swift collection methods, refer to the official Swift documentation.