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 }
问题是,就 map
和 flatMap
而言,可选值是 0 或 1 个元素的集合。您可以直接调用 map
和 flatMap
可选值而不用展开它们:
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=] }
我们有一个 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 }
问题是,就 map
和 flatMap
而言,可选值是 0 或 1 个元素的集合。您可以直接调用 map
和 flatMap
可选值而不用展开它们:
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=] }