Skip to content

Transforming a sequence into a signal of sequence #262

Open
@npvisual

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 ?

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions