Swift flatMap gives unexpected result while using with optional array

拜拜、爱过 提交于 2019-12-03 00:13:44

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 }

Why let cars: [String] is different from let cars: [String]? with flatMap ?

There are two flavours of flatMap on sequences;

1) one that flattens out sequences returned from the closure passed to it,

2) one that filters out nils from the closure passed to it (note this overload is soon to be renamed to compactMap to avoid confusion as @krunal mentioned on comment)

In your code you’re using the nil filtering overload, so the nils in your array are filtered out. It won’t however do any flattening of the nested arrays. You could call flatMap again to achieve that.

like

let flatmapArray = personsArray.flatMap{$0.cars}.flatMap{$0}
print(flatmapArray)

You need to call flatMap once more for array containing Optionals: personsArray.flatMap { $0.cars }.flatMap { $0 }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!