如何比较两个可观察对象中的项目,然后根据RxJava2中的匹配项进行过滤?
我正在尝试比较两个可观察值。两者都由具有ID和server_address的Server对象组成。
第一个可观察值表示数据库中存在的当前服务器对象。
Observable1 = [{"id":1, "server_address": "10.1.1.1},{"id":2, "server_address": "10.2.2.2},{"id":3, "server_address": "10.3.3.3}]
第二个可观察对象是根据服务器对象用户的REST请求创建的,他们希望将这些对象“添加” /“插入”到数据库中。
Observable2 = [{"id":4, "server_address": "10.1.1.1},{"id":5, "server_address": "10.4.4.4}]
我只想添加/插入与数据库中现有的server_address不匹配的新服务器。例如,如果Observable2中任何项的server_address字段与Observable1中任何项的server_address匹配,那么我想将它们过滤掉,而Observable2中只剩下真正新的/唯一的server_address项。
在上述示例中,我需要逻辑来过滤掉“ id”为4的服务器,因为数据库中已经存在具有该server_address的项。因此,我想过滤出项目编号4,但保留项目编号5。然后将项目5插入数据库。
问题是,我可以在RxJava2中使用什么操作来完成此任务?我已经看过许多有关zip或Combine的内容,但我不确定这就是我想要的。
答案 0 :(得分:0)
有多种方法可以使此方法以纯粹的反应方式工作,但是给定您的规范,它可能比使用其他方法更加复杂:首先获取要删除的所有内容,然后过滤Observable2
使用它。
将其作为伪代码,因为我不确定您要做什么(也不知道您使用哪种语言),但是它应该以某种方式起作用:
allServers = observable1
.map(s -> s['address'])
.toList()
.blockingGet() // out of the reactive world for a bit
.toSet()
observable2
.filter(s -> !allServers.contains(s['address']))
.forEach(s -> doWhateverYouWantWith(s))
如果您真的想做到100%反应性,则可能需要一种方法来区分您来自哪个可观察对象,合并结果,按地址分组,然后进行过滤。再次,用伪代码,并假设您有Map
代表每个元素:
observable1
.map(s -> s + {'source': 'db'})
.merge(observable2.map(s -> s + {'source': 'request'})
.groupBy(s -> s['address'])
.flatMap(group -> group.take(1))
.filter(s -> s['source'] == 'request')
.forEach(s -> doWhateverYouWantWith(s))
之所以可行,是因为在每个组中,您都可以选择以下一种:
答案 1 :(得分:0)
假设您的可观察对象正在发出项目列表,那么您可能希望对集合而不是可观察对象执行筛选操作。有几种方法可以做到这一点。您可以使用简单的flatMap +地图或您提到的CombineLatest / zip来实现。
示例用Kotlin编写。
val observable1 = Observable.just((1..10 step 2).toList()) // Odd integers between 1 and 10
val observable2 = Observable.just((1..10).toList()) // Integers between 1 and 10
平面地图+地图
observable1.flatMap { result1 ->
observable2.map { result2 -> result2 - result1 }
}.subscribe { println(it.toString()) }
最新组合
Observable.combineLatest<List<Int>, List<Int>, List<Int>>(
observable1,
observable2,
BiFunction { result1, result2 ->
result2.filter { item ->
!result1.contains(item)
}
})
.subscribe { println(it.toString()) }
邮政编码
Observable.zip<List<Int>, List<Int>, List<Int>>(
observable1,
observable2,
BiFunction { result1, result2 ->
result2 - result1
})
.subscribe { println(it.toString()) }
所有这些输出:
[2, 4, 6, 8, 10]
或者,如果要使用RxJava的filter运算符并单独发出每个项目,则可以使用flatMapIterable将列表转换为项目流,并对每个项目执行过滤。
observable1.flatMap { result1 ->
observable2.flatMapIterable { result2 -> result2 }
.filter { item -> !result1.contains(item) }
}.subscribe { println(it.toString()) }
输出:
2
4
6
8
10