使用 RxJava 生成一个映射,其中键是 Kotlin 枚举的值,映射的值来自另一个 RxJava 流
Posted
技术标签:
【中文标题】使用 RxJava 生成一个映射,其中键是 Kotlin 枚举的值,映射的值来自另一个 RxJava 流【英文标题】:Using RxJava to generate a map where keys are values of a Kotlin enum and map's values come from another RxJava stream 【发布时间】:2021-10-08 00:29:34 【问题描述】:简介
假设我有一个 Kotlin 枚举类:
enum class Type
ONE,
TWO,
THREE,
FOUR
以及以下数据类:
data class Item(
val name: String,
val type: Type
)
然后我有一个Single
,它发出一个Item
s 的列表——可以通过任何方式,但出于示例目的,假设它看起来像这样:
val itemsSingle = Single.just(listOf(
Item("A", Type.ONE),
Item("B", Type.ONE),
Item("C", Type.TWO),
Item("D", Type.THREE),
))
问题
我想要实现的是拥有一个 RxJava 流,它将输出一个映射,其中键来自 Type
,值是与给定 Type
值匹配的 Item
s 列表(其中未确定的、未排序的Item
s 的列表由其他一些 Single
流提供)。签名将是:
Single<Map<Type, List<Item>> // or Observable<Map<Type, List<Item>>
另一个要求是映射的键应始终耗尽 Type
枚举中的所有值,即使 itemsSingle
流不包含某些 Type
值的项目(或根本没有项目)。因此,对于提供的 itemsSingle
示例流,返回的映射应如下所示:
ONE: [ Item(name: "A", type: ONE), Item(name: "B", type: ONE) ],
TWO: [ Item(name: "C", type: TWO) ],
THREE: [ Item(name: "D", type: THREE) ],
FOUR: []
尝试
通过以上所有步骤,我已经通过以下步骤达到了预期的结果:
-
为了满足用尽所有
Type
枚举值的要求,我首先创建一个映射,其中包含所有可能的 Type
值的空列表:
val typeValuesMap = Type.values().associate it to emptyList<Item>()
val typeValuesMapSingle = Single.just(typeValuesMap)
// result: ONE=[], TWO=[], THREE=[], FOUR=[]
-
我可以得到一张地图,其中包含来自
itemsSingle
的项目,这些项目分组在各自的 Type
值键下:
val groupedItemsMapSingle = itemsSingle.flattenAsObservable it
.groupBy it.type
.flatMapSingle it.toList()
.toMap list -> list[0].type // the list is guaranteed to have at least one item
// result: ONE=[Item(name=A, type=ONE), Item(name=B, type=ONE)], THREE=[Item(name=D, type=THREE)], TWO=[Item(name=C, type=TWO)]
-
最后我可以使用 combineLatest 运算符合并两个列表,并覆盖给定
Type
值的初始空项目列表:
Observable.combineLatest(
typeValuesMapSingle.flattenAsObservable it.entries ,
groupedItemsMapSingle.flattenAsObservable it.entries
) a, b -> listOf(a, b)
.defaultIfEmpty(typeValuesMap.entries.toList()) // in case itemsSingle is empty
.flatMapIterable it
.collect(mutableMapOf<Type, List<Item>>(), a, b -> a[b.key] = b.value)
// result: FOUR=[], ONE=[Item(name=A, type=ONE), Item(name=B, type=ONE)], THREE=[Item(name=D, type=THREE)], TWO=[Item(name=C, type=TWO)]
总结
如您所见,对于一个看似简单的操作,它的代码量相当多。所以我的问题是——有没有更简单的方法来达到我想要的结果?
【问题讨论】:
【参考方案1】:只需将空列表映射与填充列表映射合并
val result = itemsSingle.map items->
Type.values().associateWith listOf<Item>() + items.groupBy it.type
【讨论】:
以上是关于使用 RxJava 生成一个映射,其中键是 Kotlin 枚举的值,映射的值来自另一个 RxJava 流的主要内容,如果未能解决你的问题,请参考以下文章