Blog

Swift Tip: In-Place Map

When we find ourselves repeating code on both the left-hand and right-hand side of an assignment operator, it is often a hint that we could be using a mutating method instead (for example, we could use toggle on Bool).

Consider the following example:

struct User {
    var favorites: [String]
}

var users = [
    "ida": User(favorites: ["https://www.objc.io"])
]

Now let’s say we want to change the favorites for ida: we’d like to replace each “https” with “http”. It’s not uncommon to see code like this:

// Check if the key is present
if var u = users["ida"] {
    // Modify a nested property
    u.favorites = u.favorites.map {
        $0.replacingOccurrences(of: "https", with: "http")
    }
    // Re-assign the new value
    users["ida"] = u
}

There are a few things that are tricky in the code above: we need to make sure that the key matches in both the lookup and the assignment, and the repetition of favorites in the assignment is also not so nice. Ideally, we’d write this in a single line:

users["ida"]?.favorites = (users["ida"].favorites ?? []).map { /* ... */ }

This still has duplication on either side of the assignment operator, and the nil coalescing is distracting from what we’re trying to say. Instead, we could define a version of map that mutates the array in place:

extension Array {
    mutating func mapInPlace(_ transform: (Element) -> Element) {
        self = map(transform)
    }
}

Now we can write our code without duplication:

users["ida"]?.favorites.mapInPlace {
    $0.replacingOccurrences(of: "https", with: "http")
}

If you like this approach, you can make it available to many more types by writing mapInPlace on MutableCollection. If you like mutation, the transform could be written in inout-style as well.

In Swift Talk 21 (a public episode), we look at other ways to work with structs. Our book, Advanced Swift, covers mutating, inout, and value types in depth.

Subscribers make our public episodes possible.

To support us, you can subscribe too.


Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts