# Data Transformation in Swift

{% hint style="success" %}
[**Source Code**](https://github.com/ivansaul/SwiftUI-Cookbook/blob/master/src/Swift/DataTransformationInSwift.swift) <img src="/files/dlykackBgGW8J1PA46y5" alt="" data-size="original">
{% endhint %}

Swift offers a rich toolkit for manipulating collections of data. When it comes to transforming elements within a collection, four key functions shine: `map`, `flatMap`, `compactMap`, and `tryMap`. While they share similarities, each tackles a specific data transformation scenario. Let's delve into their functionalities and explore when to use each one effectively.

## `map`: The Versatile Transformer

Imagine you have a list of names and want to convert them all to uppercase. `map` comes to the rescue! It applies a transformation you define (using a closure) to each element in a collection and returns a new collection with the transformed results.

Here's an example:

```swift
let names = ["Alice", "Bob", "Charlie"]
let uppercaseNames = names.map { $0.uppercased() }
print(uppercaseNames) // ["ALICE", "BOB", "CHARLIE"]
```

In this instance, the closure `$0.uppercased()` capitalizes each name in the `names` list. `map` creates a new list (`uppercaseNames`) containing the transformed names.

## `flatMap`: Unnesting Collections with Ease

What if your collection contains nested collections, and you want to create a single, flat list? Enter `flatMap`. It iterates through a collection, applies a transformation, and then "flattens" the results into a single collection.

Consider a list of customer orders, where each order has a list of items:

```swift
struct Order {
  let items: [String]
}

let orders = [
  Order(items: ["A", "B"]),
  Order(items: ["C", "D"])
]
```

We can use `flatMap` to extract all items from these orders into a single list:

```swift
let allItems = orders.flatMap { $0.items }
print(allItems) // ["A", "B", "C", "D"]
```

`flatMap` transforms each order by returning its `items` list. Since these are nested lists, `flatMap` flattens them into a single list containing all the individual items.

## `compactMap`: Filtering and Transforming Simultaneously

Sometimes, you might have a collection containing optional values (`nil` or a valid value). `compactMap` is your friend here. It applies a transformation like `map`, but it also filters out any optional values that turn into `nil` during the transformation.

For example, suppose you have a list of ages stored as strings, but some might be invalid:

```swift
let ages = ["25", "unknown", "30"]
```

You can use `compactMap` to convert valid ages to integers and discard any invalid strings:

```swift
let validAges = ages.compactMap { Int($0) }
print(validAges) // [25, 30]
```

Here, `compactMap` attempts to convert each age string to an integer using `Int($0)`. If the conversion fails (e.g., for "unknown"), `compactMap` discards it. Otherwise, it includes the converted integer in the new `validAges` list.

## `tryMap`: Handling Errors During Transformation

When dealing with functions that might throw errors, `tryMap` provides a safe way to transform elements. It's similar to `map`, but it can handle errors that arise during the transformation.

Imagine a function `calculateDiscount` that throws an error for invalid product IDs:

```swift
func calculateDiscount(productId: String) throws -> Double {
  // Logic to calculate discount (potentially throwing an error)
}
```

Let's say you have a list of product IDs and want to calculate discounts, but some IDs might be invalid:

```swift
let productIds = ["A123", "invalid", "B456"]
```

With `tryMap`, you can attempt the calculation while catching any errors:

```swift
do {
  let discounts = try productIds.tryMap { try calculateDiscount(productId: $0) }
  print(discounts) // [calculated discount for A123, calculated discount for B456]
} catch {
  print("Error calculating discount: \(error)")
}
```

`tryMap` tries to call `calculateDiscount` for each ID. If successful, it includes the calculated discount in the `discounts` list. If an error occurs (e.g., for "invalid" ID), `tryMap` throws the error


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ivansaul.gitbook.io/swiftui-cookbook/swift/continued-learning/data-transformation-in-swift.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
