We have an array of the Person objects and each object has another array of String, which is optional. We want the consolidated list of car names in our society.
The issue is that for the purposes of map
and flatMap
, optionals are collections of 0 or 1 elements. You can directly call map
and flatMap
on optionals without unwrapping them:
let foo: Int? = 5
foo.map { $0 * $0 } // Int? = 25; "collection of one element"
let bar: Int? = nil
bar.map { $0 * $0 } // Int? = nil; "collection of zero elements"
To illustrate in more familiar terms your current situation, you're looking at the equivalent of this:
class Person {
let cars: [[String]]
}
If you had a var persons: [Person]
and called persons.flatMap { $0.cars }
, the resulting type of this operation would unquestionably be [[String]]
: you start out with three layers of collections and you end up with two.
This is also effectively what is happening with [String]?
instead of [[String]]
.
In the case that you are describing, I would advise dropping the optional and using empty arrays. I'm not sure that the distinction between a nil
array and an empty
array is truly necessary in your case: my interpretation is that a nil array means that the person is incapable of owning a car, whereas an empty array means that the person is capable of owning a car but doesn't have any.
If you cannot drop the optional, then you will need to call flatMap
twice to flatten two layers instead of only one:
persons.flatMap { $0.cars }.flatMap { $0 }