RXJS: combinar alternativamente elementos de corrientes

votos
4

Me gustaría combinar alternativamente elementos de múltiples flujos:

var print = console.log.bind(console);

var s1 = Rx.Observable.fromArray([1, 1, 5]);
var s2 = Rx.Observable.fromArray([2, 9]);
var s3 = Rx.Observable.fromArray([3, 4, 6, 7, 8]);

alternate(s1, s2, s3).subscribe(print); // 1, 2, 3, 1, 9, 4, 5, 6, 7, 8

¿Cómo se ve la definición de la función de alternate?

Publicado el 22/02/2015 a las 08:51
fuente por usuario
En otros idiomas...                            


2 respuestas

votos
5

Usar zip y concatMap cuando se trabaja en observables que se crearon a partir de matrices (como en el ejemplo), o zip y flatMap cuando se trabaja en observables que son inherentemente asíncrona.

Rx.Observable
  .zip(s1, s2, s3, function(x,y,z) { return [x,y,z]; })
  .concatMap(function (list) { return Rx.Observable.from(list); })
  .subscribe(print); // 1, 2, 3, 1, 9, 4

Nótese que esto no procede más una vez que uno de los observables fuente completa. Eso es porque zipes estrictamente "equilibrado" y espera hasta que todas las fuentes tienen un evento coincidente. Lo que queremos es una versión algo suelto de cremallera cuando se trata de fuentes completado.

Respondida el 23/02/2015 a las 05:51
fuente por usuario

votos
3

Si hay un valor (por ejemplo undefined) que no es emitida por los observables de origen, esta solución funciona:

var concat = Rx.Observable.concat;
var repeat = Rx.Observable.repeat;
var zipArray = Rx.Observable.zipArray;
var fromArray = Rx.Observable.fromArray;

var print = console.log.bind(console);

var s1 = fromArray([1, 1, 5]);
var s2 = fromArray([2, 9]);
var s3 = fromArray([3, 4, 6, 7, 8]);

alternate(s1, s2, s3).subscribe(print);

function alternate() {
    var sources = Array.slice(arguments).map(function(s) {
        return concat(s, repeat(undefined))
    });
    return zipArray(sources)
            .map(function(values) {
                return values.filter(function(x) {
                    return x !== undefined;
                });
            }).takeWhile(function(values) {
                return values.length > 0;
            }).concatMap(function (list) { return fromArray(list); })
}

Mismo ejemplo en la ES6:

const {concat, repeat, zipArray, fromArray} = Rx.Observable;

var print = console.log.bind(console);

var s1 = fromArray([1, 1, 5]);
var s2 = fromArray([2, 9]);
var s3 = fromArray([3, 4, 6, 7, 8]);

alternate(s1, s2, s3).subscribe(print);

function alternate(...sources) {
    return zipArray(sources.map( (s) => concat(s, repeat(undefined)) ))
            .map((values) => values.filter( (x) => x !== undefined ))
            .takeWhile( (values) => values.length > 0)
            .concatMap( (list) => fromArray(list) )
}
Respondida el 23/02/2015 a las 07:58
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more