Mira estas 2 pequeñas pruebas:
@Test
public void test1() {
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.flatMap(group -> {
if (group.getKey()) {
return group;
}
return group;
})
.subscribe(System.out::println);
}
@Test
public void test2() {
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.toMap(g -> g.getKey())
.flatMapObservable(m -> Observable.merge(
m.get(true),
m.get(false)))
.subscribe(System.out::println);
}
Yo estaba esperando tanto para devolver una lista de números en el mismo orden, por lo que:
1 2 3 4 5 6 7 8 9 10
Pero el ejemplo el segundo reenvíos
2 4 6 8 10 1 3 5 7 9
en lugar.
Parece que en el segundo ejemplo, el merge
está haciendo un concat
cambio, de hecho, si lo cambio a una concat
, el resultado es el mismo.
¿Qué me estoy perdiendo?
Gracias.
Básicamente flatMap
y merge
no garantizan el orden de los artículos emitidos.
De flatMap doc:
Tenga en cuenta que FlatMap fusiona las emisiones de estos observables, de modo que puedan intercalar.
De fusión doc:
De mezcla puede intercalar los artículos emitidos por los observables fusionadas (un operador similares, de concatenación, hace artículos no intercalación, pero emite todos los elementos de cada fuente observables a su vez antes de comenzar a emitir los artículos en la siguiente fuente observable).
Citar de este SO respuesta :
En su caso, con un solo elemento, corrientes estáticas, no está haciendo una diferencia real (pero en teoría, podría fusión palabras de salida en orden aleatorio y aún así ser válida de acuerdo a las especificaciones)
Si necesita un uso para garantizar concat*
su lugar.
primer ejemplo
Funciona así:
- cuando
1
se emite elgroupBy
operador creará unaGroupedObservable
con llavefalse
flatMap
dará salida a los artículos de este observable - que es en la actualidad sólo1
- cuando
2
se emite elgroupBy
operador creará unaGroupedObservable
con llavetrue
flatMap
Ahora también tendrá salida los artículos de este segundoGroupedObservable
- que se encuentra actualmente2
- cuando
3
se emite elgroupBy
operador de la añadirá a la ya existenteGroupedObservable
con llavefalse
y laflatMap
voluntad saldrá este elemento de inmediato - cuando
4
se emite elgroupBy
operador de la añadirá a la ya existenteGroupedObservable
con llavetrue
y laflatMap
voluntad saldrá este elemento de inmediato - etcétera
Puede ayudarle a añadir un poco más de registro:
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.doOnNext(group -> System.out.println("key: " + group.getKey()))
.flatMap(group -> {
if (group.getKey()) {
return group;
}
return group;
})
.subscribe(System.out::println);
A continuación, la salida es:
key: false
1
key: true
2
3
...
El segundo ejemplo
Esto es muy diferente, porque toMap
se bloqueará hasta que se complete aguas arriba:
- cuando
1
se emite elgroupBy
operador creará unaGroupedObservable
con llavefalse
toMap
agregará esteGroupedObservable
al mapa interno y utiliza la clavefalse
(la misma tecla que laGroupedObservable
tiene)
- cuando
2
se emite elgroupBy
operador creará unaGroupedObservable
con llavetrue
toMap
agregará esteGroupedObservable
al mapa interno y utiliza la clavetrue
(la misma tecla que laGroupedObservable
tiene) - por lo que ahora el mapa tiene 2GroupedObservables
- los números siguientes se añaden a los correspondientes
GroupedObservables
y cuando finaliza el origen, eltoMap
operador está hecho y pasará el mapa para el siguiente operador - en el
flatMapObservable
que utilizar el mapa para crear un nuevo observable donde se añade por primera vez los elementos clave pares (=true
) y luego los elementos impares (clave =false
)
También en este caso se podría añadir un poco más de registro:
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.doOnNext(group -> System.out.println("key: " + group.getKey()))
.toMap(g -> g.getKey())
.doOnSuccess(map -> System.out.println("map: " + map.size()))
.flatMapObservable(m -> Observable.merge(
m.get(true),
m.get(false)
))
.subscribe(System.out::println);
A continuación, la salida es:
key: false
key: true
map: 2
2
4
6
8
10
1
3
5
7
9