使用可选数组时,Swift flatMap会产生意外结果
我们有一个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)
//预期结果:[“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())
结果是:
[[“i20”,“Swift VXI”],[“Crita”,“Swift VXI”],[]]
仍然不是预期的结果。
如果我从汽车数组中删除可选,如,
let cars: [String] Person(name:"Amit", address:"Nagpure, India", age:17, income: 200000.0, cars:Array())
然后它按预期工作。
结果:
[“i20”,“Swift VXI”,“Crita”,“Swift VXI”]
如果成员类型为Collection是可选的,我不确定为什么它不给出上述结果?
问题是,出于map
和flatMap
的目的,optionals是0或1个元素的集合。 您可以直接在选项上调用map
和flatMap
而无需解包它们:
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"
为了用更熟悉的术语说明您当前的情况,您正在研究相当于:
class Person { let cars: [[String]] }
如果你有一个var persons: [Person]
并且调用persons.flatMap { $0.cars }
,那么这个操作的结果类型无疑会是[[String]]
:你从三层集合开始,你最终得到两个。
这也是[String]?
实际发生的事情[String]?
而不是[[String]]
。
在您描述的情况下,我建议删除可选和使用空数组。 在你的情况下,我不确定nil
数组和empty
数组之间的区别是真正必要的:我的解释是nil数组意味着该人无法拥有汽车,而空数组意味着该人是能够拥有一辆车,但却没有。
如果你不能删除可选项,那么你需要调用flatMap
两次来展平两层而不是只有一层:
persons.flatMap { $0.cars }.flatMap { $0 }
为什么let cars: [String]
与let cars: [String]?
不同let cars: [String]?
用flatMap
?
sequences
上有两种flatMap
;
1)一个扁平化从闭包返回的序列传递到它,
2)从传递给它的闭包过滤掉nils(注意这个重载很快将被重命名为compactMap以避免混淆,如@krunal在评论中提到的)
在您的代码中,您使用的是nil过滤重载,因此过滤掉了数组中的nils。 但是,它不会对嵌套数组进行任何展平。 你可以再次调用flatMap来实现这一点。
喜欢
let flatmapArray = personsArray.flatMap{$0.cars}.flatMap{$0} print(flatmapArray)
对于包含Optionals的数组,您需要再次调用flatMap
:personsArray.flatMap {$ 0.cars} .flatMap {$ 0}