Swift flatMap 在与可选数组一起使用时给出意外结果

Swift flatMap gives unexpected result while using with optional array

我们有一个 Person 对象数组,每个对象都有另一个 String 数组,这是可选的。 我们想要我们社会中汽车名称的综合列表。

struct Person {
    let name: String
    let address: String
    let age: Int
    let income: Double
    let cars: [String]?
}
let personsArray = [Person(name:"Santosh", address: "Pune, India", age:34, income: 100000.0, cars:["i20","Swift VXI"]),
                   Person(name: "John", address:"New York, US", age: 23, income: 150000.0, cars:["Crita", "Swift VXI"]),
                   Person(name:"Amit", address:"Nagpure, India", age:17, income: 200000.0, cars:nil)]

let flatmapArray = personsArray.flatMap({[=11=].cars})
print(flatmapArray)

// Expected Result: ["i20", "Swift VXI", "Crita", "Swift VXI"]

// Result: [["i20", "Swift VXI"], ["Crita", "Swift VXI"]]

为什么它没有给我一个字符串数组作为结果?

我对上面的代码做了一些修改,如下所示, 我们尝试将空数组传递给第三个人对象,而不是 "nil"。

Person(name:"Amit", address:"Nagpure, India", age:17, income: 200000.0, cars:Array())

结果是:

[["i20", "Swift VXI"], ["Crita", "Swift VXI"], []]

仍然不是预期的结果。

如果我从 cars 数组中删除可选项,例如

let cars: [String]  
Person(name:"Amit", address:"Nagpure, India", age:17, income: 200000.0, cars:Array()) 

然后它按预期工作。

结果:

["i20", "Swift VXI", "Crita", "Swift VXI"]

我不确定如果成员类型为 Collection is optional,为什么不给出上述结果?

为什么 let cars: [String]let cars: [String]?flatMap 不同?

sequences 上有两种口味的 flatMap

1) 将传递给它的闭包返回的序列展平,

2) 一个从传递给它的闭包中过滤掉 nils 的方法(注意这个重载很快将被重命名为 compactMap 以避免混淆,正如@krunal 在评论中提到的那样)

在您的代码中,您使用了 nil 过滤重载,因此数组中的 nils 被过滤掉了。然而,它不会对嵌套数组进行任何展平。您可以再次调用 flatMap 来实现。

喜欢

let flatmapArray = personsArray.flatMap{[=10=].cars}.flatMap{[=10=]}
print(flatmapArray)

您需要为包含 Optionals 的数组再次调用 flatMap: personsArray.flatMap { $0.cars }.flatMap { $0 }

问题是,就 mapflatMap 而言,可选值是 0 或 1 个元素的集合。您可以直接调用 mapflatMap 可选值而不用展开它们:

let foo: Int? = 5
foo.map { [=10=] * [=10=] } // Int? = 25; "collection of one element"
let bar: Int? = nil
bar.map { [=10=] * [=10=] } // Int? = nil; "collection of zero elements"

为了以更熟悉的方式说明您当前的情况,您正在查看与此等效的内容:

class Person {
    let cars: [[String]]
}

如果你有一个 var persons: [Person] 并调用 persons.flatMap { [=18=].cars },这个操作的结果类型无疑是 [[String]]:你从三层集合开始,最后是两个。

这实际上也是 [String]? 而不是 [[String]] 的情况。

在您描述的情况下,我建议删除可选的并使用空数组。我不确定 nil 数组和 empty 数组之间的区别在您的情况下是否真的有必要:我的解释是 nil 数组意味着该人无法拥有汽车,而空数组表示此人有能力拥有汽车但没有。

如果你不能删除可选的,那么你将需要调用 flatMap 两次来展平两层而不是一层:

persons.flatMap { [=12=].cars }.flatMap { [=12=] }