映射组合数组时如何避免嵌套闭包?



我有一个字符串数组,我想将其映射到不同的对象中。我正在使用map将数组转换为另一个数组,但它非常嵌套:

$favorites
.map { articleIDs in
articleIDs.compactMap { id in
state.articles.first { $0.id == id }
}
}
.assign(to: Self.favorites, on: self)
.store(in: &cancellable)

是否有将转换应用于每个单独项目的简写?我最初试图这样做,但它没有用:

state.$favorites
.mapEach { id in state.articles.first { $0.id == id } }
.assign(to: Self.favorites, on: self)
.store(in: &cancellable)

这里有一种方法可以做到这一点,你:

  1. 使用Publishers.Sequence将单个数组转换为单个元素的管道
  2. 单独处理元素。
  3. 使用collect运算符将元素转换回数组。

下面是一个可以在 Xcode 游乐场中运行的人为示例:

import Combine
import UIKit
class MyStore: ObservableObject {
@Published var favorites: [(id: Int, title: String)] = []
let articles = [
(id: 22, title: "foo"),
(id: 5, title: "bar"),
(id: 13, title: "baz"),
]
var cancellable: Set<AnyCancellable> = []
func addFavorites(favorites: AnyPublisher<[Int], Never>) {
let articles = self.articles
favorites
.flatMap(Publishers.Sequence.init)
.compactMap { fav in articles.first { fav == $0.id }}
.collect()
.assign(to: .favorites, on: self)
.store(in: &cancellable)
}
}
let store = MyStore()
store.addFavorites(favorites: Just([22, 13]).eraseToAnyPublisher())
print(store.favorites)
// => [(id: 22, title: "foo"), (id: 13, title: "baz")]

。但是我怀疑这实际上不是您想要的。更优雅的解决方案可能是创建一个定制的compactMapEach运算符。如下所示:

extension Publisher {
public func compactMapEach<T, U>(_ transform: @escaping (T) -> U?)
-> Publishers.Map<Self, [U]>
where Output == [T]
{
return map { $0.compactMap(transform) }
}
}

最新更新