如何做一个组,并使用RxJava和Kotlin收集?

我有Observable和Rate是一个简单的对象:

 Rate(val value:String){} Rates(val rates: List) 

我想将Observable改为Observable<HashMap

Rates(arrayOf(Rate("1"),Rate("2"), Rate("3"),Rate("3"), Rate("2"),Rate("2")))我期望的结果:

 (1 -> 1) (2 -> 3) (3 -> 2) (4 -> 0) (5 -> 0) 

我开始创建这样的东西:

 service.getRates() .flatMap {it-> Observable.from(it.rates) } .filter { !it.value.isNullOrEmpty() } .groupBy {it -> it.value} .collect({ HashMap()}, { b, t -> b.put(t.key, t.count???)} 

但我卡在这里,我不知道所有的价值? 我不知道如何添加空值(0),如果没有5个4.有没有办法使用rx做到这一点?

请查看代码中的注释以解答您的问题。

 import rx.Observable fun main(args: Array) { val service = Service() // This adds all keys with each key mapped to zero val referenceKeyCounts = Observable .just("1", "2", "3", "4", "5") .map { it to 0 } val keyCountsFromService = service.getRates() .flatMap { Observable.from(it.rates) } .filter { !it.value.isNullOrEmpty() } .map { it.value to 1 } // map each occurrence of key to 1 Observable.concat(referenceKeyCounts, keyCountsFromService) .groupBy { it.first } .flatMap { group -> // this converts GroupedObservable to final values group.reduce(0, { acc, pair -> acc + pair.second }) // add instead of counting .map { group.key to it } } .subscribe(::println) } class Service { fun getRates(): Observable = Observable.just(Rates(listOf( Rate("1"), Rate("2"), Rate("3"), Rate("3"), Rate("2"), Rate("2") ))) } class Rate(val value: String) class Rates(val rates: List) 

诀窍是在GroupedObservable上使用count ,因为它只在源observable完成时才发出单个值:

在这里输入图像说明

从那里:

 rates .flatMap { Observable.from(it.rates) } .filter { !it.value.isNullOrEmpty() } .groupBy { it.value } .flatMap { group -> group.count().map { group.key to it } } // list "1"->1, "2"->3, ... .mergeWith(Observable.from((1..5).map { it.toString() to 0 })) // defaults "4"->0 .reduce(mutableMapOf()) { acc, cur -> acc.apply { val (key, count) = cur this[key] = (this[key] ?: 0) + count // add counts } }.subscribe { countedRates -> println(countedRates) } 

我认为这更多是关于函数式编程而不是RxJava相关的问题

Rates -> Map实现一个映射函数。

技巧:合并Pair两个列表以形成一个Map

 val ratesToMapWithEmptyValues: (Rates) -> Map = { source -> //TODO: Just for demo val validRatesValue = arrayOf("1","2","3","4","5") mapOf( *validRatesValue.map { it to 0 }.toTypedArray(), *source.rates.groupBy(Rate::value).mapValues { it.value.size }.toList().toTypedArray() ) } 

Observable.map应用该函数

 service.getRates() .map(ratesToMapWithEmptyValues)