Transforming a sequence into a signal of sequence #262
Description
Context
I am finding, more often than not, that I am in need to transform a sequence (dictionary or array) into a signal of sequence.
This could happen either from an existing signal being flatMap'd to a sequence or simply an existing sequence from the imperative world that I need to transform (say via an API call on each element of the sequence) into a signal of sequence.
Taking the example of the chat room in AbsurdGitter. Let's imagine for a second that the Room entity holds a reference to the participants in the room, so something like :
public struct Room: Codable {
public let id: String
public let name: String // Room name.
public let uri: String? // Room URI on Gitter.
public let topic: String // Room topic. (default: GitHub repo description)
public let participants: [String: Bool]? <----- // Participants in the chat room, with the boolean indicating of they are currently active
....
public let githubType: String // Type of the room.
public let tags: [String] // Tags that define the room.
}
A roomSignal
can get me the currently selected room from which I can retrieve the active participants, as such :
roomSignal
.compactMap { $0.participants } // participants for the room given by the signal
.map { $0.filter { $0.value } } // we filter only the active participants
But if I want to transform the resulting signal into a signal of array of Users (retrieved from an API call to a third party backend), so that I can display the list of users in the room, then I always hit a snag :
roomSignal
.compactMap { $0.participants } // participants for the room given by the signal
.map { $0.filter { $0.value } } // we filter only the active participants
.flatMapLatest { seq -> Signal<[Participant], ApplicationError> in
seq
.{ User.me(with: $0.key).response(using: client) }
.?????
}
So I am now left with a sequence (dictionary) in the flatMapLatest that will be transformed into an array of signals, when, what I want is a signal of sequence.
So :
Signal<[Participant], ApplicationError>
vs.
[Signal<Participant, ApplicationError>]
Note : using a combination of .flattenElements()
and .collect()
certainly makes things a lot easier. However, as mentioned in issue #209 , that will not work unless I prematurely finish the roomSignal
-- of course, I might actually be doing something really stupid (wouldn't put that past me!) and then using .flattenElements()
and .collect()
would be the way to go !
Solution
If we extend Sequence to add a toSignal()
method, with a transform function, that could potentially make things a lot smoother :
extension Sequence {
public func toSignal<ElementOfResult>(_ transform: @escaping (Iterator.Element) -> Signal<ElementOfResult, Error>) -> Signal<[ElementOfResult], Error> {
return Signal { observer in
var collect: [ElementOfResult] = []
self.forEach { transform($0).observeNext { result in collect.append(result) } }
observer.receive(collect)
return observer
}
}
}
I am just not sure that this is the right approach. Is there a better way to solve this problem ?