使用可选数组时,Swift flatMap会产生意外结果

San*_*tre 8 ios flatmap swift

我们有一个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({$0.cars})
print(flatmapArray)
Run Code Online (Sandbox Code Playgroud)

//预期结果:["i20","Swift VXI","Crita","Swift VXI"]

//结果:[["i20","Swift VXI"],["Crita","Swift VXI"]]

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

我在上面的代码中做了几处更改,如下面的代码,而不是"nil",我们尝试将空数组传递给第3个Person对象.

Person(name:"Amit", address:"Nagpure, India", age:17, income: 200000.0, cars:Array())
Run Code Online (Sandbox Code Playgroud)

结果是:

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

仍然不是预期的结果.

如果我从汽车数组中删除可选,如,

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

然后它按预期工作.

结果:

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

如果成员类型为Collection是可选的,我不确定为什么它不给出上述结果?

zne*_*eak 8

的问题是,为的目的mapflatMap,自选是0或1的元素集合.你可以直接打电话mapflatMap打开选项而不打开它们:

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"
Run Code Online (Sandbox Code Playgroud)

为了用更熟悉的术语来说明你目前的情况,你正在寻找相当于这个:

class Person {
    let cars: [[String]]
}
Run Code Online (Sandbox Code Playgroud)

如果你有一个var persons: [Person]并且被调用persons.flatMap { $0.cars },那么这个操作的结果类型无疑会是[[String]]:你从三层集合开始,最后得到两个.

这也是实际发生的事情,[String]?而不是[[String]].

在您描述的情况下,我建议删除可选和使用空数组.我不确定在你的情况下nil数组和empty数组之间的区别是真正必要的:我的解释是nil数组意味着该人无法拥有汽车,而空数组意味着该人能够拥有一辆车但却没有.

如果您无法删除可选项,则需要调用flatMap两次以展平两个图层而不是仅一个图层:

persons.flatMap { $0.cars }.flatMap { $0 }
Run Code Online (Sandbox Code Playgroud)