[-6ren">
gpt4 book ai didi

Swift:延迟封装 map、filter、flatMap 链

转载 作者:搜寻专家 更新时间:2023-10-30 22:05:44 26 4
gpt4 key购买 nike

我有一份动物 list :

let animals = ["bear", "dog", "cat"]

以及转换该列表的一些方法:

typealias Transform = (String) -> [String]

let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural: Transform = { [$0 + "s"] }
let double: Transform = { [$0, $0] }

顺便说一句,它们分别类似于 filter(输出 0 或 1 个元素)、map(恰好 1 个元素)和 flatmap(多于 1 个元素),但以统一的方式定义,以便可以一致地处理它们。

我想创建一个惰性迭代器,它将这些转换的数组应用于动物列表:

extension Array where Element == String {
func transform(_ transforms: [Transform]) -> AnySequence<String> {

return AnySequence<String> { () -> AnyIterator<String> in
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()

return AnyIterator {
return iterator.next()
}
}
}
}

这意味着我可以懒惰地做:

let transformed = animals.transform([containsA, plural, double])

检查结果:

print(Array(transformed))

我对它的简洁明了感到满意:

        .flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])

是一个问题,因为它意味着转换函数将仅适用于包含 3 个转换的数组。

编辑:我试过:

  var lazyCollection = self.lazy
for transform in transforms {
lazyCollection = lazyCollection.flatMap(transform) //Error
}
var iterator = lazyCollection.makeIterator()

但在标记的行上出现错误:

无法将类型“LazyCollection< FlattenCollection< LazyMapCollection< Array< String>, [String]>>>”的值分配给类型“LazyCollection< Array< String>>”

这是我理解的,因为每次循环都会添加另一个平面图,所以类型会发生变化。

如何使变换函数与任意数量的变换数组一起工作?

一个用于有限数量转换的 WET 解决方案是(但是 YUK!)

  switch transforms.count {
case 1:
var iterator = self
.lazy
.flatMap(transforms[0])
.makeIterator()
return AnyIterator {
return iterator.next()
}
case 2:
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.makeIterator()
return AnyIterator {
return iterator.next()
}
case 3:
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
default:
fatalError(" Too many transforms!")
}

完整代码:

let animals = ["bear", "dog", "cat"]

typealias Transform = (String) -> [String]

let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural: Transform = { [$0 + "s"] }
let double: Transform = { [$0, $0] }

extension Array where Element == String {
func transform(_ transforms: [Transform]) -> AnySequence<String> {

return AnySequence<String> { () -> AnyIterator<String> in
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()

return AnyIterator {
return iterator.next()
}
}
}
}

let transformed = animals.transform([containsA, plural, double])

print(Array(transformed))

最佳答案

如果您在 Sequence 协议(protocol)(而不是 Array)上定义方法,则可以递归地应用转换。如果将转换参数定义为 (Element) -> [Element] 的数组,则也不需要约束 where Element == String

extension Sequence {
func transform(_ transforms: [(Element) -> [Element]]) -> AnySequence<Element> {
if transforms.isEmpty {
return AnySequence(self)
} else {
return lazy.flatMap(transforms[0]).transform(Array(transforms[1...]))
}
}
}

关于Swift:延迟封装 map、filter、flatMap 链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54386361/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com