Swift optionals, map and filter


Lets imagine following situation. We have Person class which can look something like this:

public class Person {

    var firstName: String?
    var middleName: String?
    var lastName: String?

    init(firstName: String?, middleName: String?, lastName: String?) {

        self.firstName = firstName
        self.lastName = lastName
        self.middleName = middleName
    }
}

Now, we want to get Person fullName which is basically:


var fullName = person.firstName + " " + person.middleName + " " + person.lastName

But, it is not that simple, we have to take care of optional values because all of Person components can be nil or even an empty String.

If we try to solve this in standard way, we could easily end up with something like this:


var fullName = ""
if let firstName = person.firstName where count(firstName) > 0 {
    fullName = firstName
    if let middleName = person.middleName where count(middleName) > 0 {
        fullName = fullName + " " + middleName
        if let lastName = person.lastName where count(lastName) > 0 {
            fullName = fullName + " " + lastName
        }
    } else if let lastName = person.lastName where count(lastName) > 0 {
        fullName = fullName + " " + lastName
    }
} else if let middleName = person.middleName where count(middleName) > 0  {
    fullName = fullName + " " + middleName
    if let lastName = person.lastName where count(lastName) > 0  {
        fullName = fullName + " " + lastName
    }
} else if let lastName = person.lastName where count(lastName) > 0  {
    fullName = lastName
}

This looks ugly and it is a lot of code for relatively simple thing. Also, it is not scalable. If we add more variables, we have to add checks for them on more then one place.

We can achieve much nicer solution with Swifts map and filter.

let fullNameComponents: [String?] = [person.firstName, person.middleName, person.lastName]
let filteredFullNameComponents = fullNameComponents.map{$0 ?? ""}.filter{$0 != ""}
let fullName1 = " ".join(filteredFullNameComponents)

Nicer, cleaner and scalable.

What are we doing here?

We map over fullName components and return current component or empty string if component is nil. With this step, we have got rid of optionals and now we have array of strings. In second step we are filtering components that are not empty string.

There might be easier ways to solve this problem then our initial solution, but this example shows how powerful Swift map, filter and reduce can be.