如何比较两个可观察项中的项,然后根据RxJava2中的匹配项进行过滤?

时间:2019-03-18 18:49:41

标签: observable rx-java2

如何比较两个可观察对象中的项目,然后根据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的内容,但我不确定这就是我想要的。

2 个答案:

答案 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))

之所以可行,是因为在每个组中,您都可以选择以下一种:

  • 只有一个'db'元素(将被过滤掉)
  • 一个“ db”和一个“ request”元素(由于“ db”总是最先出现,因此将被滤除)
  • 只有一个“ request”元素(将通过过滤器)

答案 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