【发布时间】:2023-04-08 01:57:01
【问题描述】:
我有两个可观察的:
- 表示复选框输入列表的可观察对象。
- 表示来自服务器的事件流的可观察对象。
我想使用来自第一个的值过滤第二个 observable。
从服务器接收到的值包括一个tag 属性,它对应于复选框列表中的值。上述两者结合产生的 observable 只会产生来自服务器的值,其 tag 属性包含在选中的复选框中。
【问题讨论】:
标签: rxjs reactive-extensions-js
我有两个可观察的:
我想使用来自第一个的值过滤第二个 observable。
从服务器接收到的值包括一个tag 属性,它对应于复选框列表中的值。上述两者结合产生的 observable 只会产生来自服务器的值,其 tag 属性包含在选中的复选框中。
【问题讨论】:
标签: rxjs reactive-extensions-js
您可以使用withLatestFrom。
.
source.withLatestFrom(checkboxes, (data, checkbox) => ({data, checkbox}))
.filter(({data, checkbox}) => ...)
这里,checkboxes 是一个表示复选框输入列表的可观察对象。 source 是一个 observable,表示来自服务器的事件流。在过滤功能中,您可以检查数据是否与复选框设置相比有效并让它通过。
请注意,checkboxes 在流可以发出任何东西之前发出至少 1 个值是很重要的。
附言。关于其他答案,即使来源是cold,此解决方案也有效。
【讨论】:
rxjs 标签。所以我添加了该注释,因为withLatestFrom 运算符在java implementation 中用@Experimental 注释(假设RxJava 版本为1.X)。我的错!
withLatestFrom 在 RxJava 2 中没有实验标签。
为了使用流B的值过滤流A,您需要观察流B并使用最新的值来过滤流A。
使用switch() 将 B observable 转换为 observable,从 A observable 产生值。
checkedInputValuesSource
.map(function (options) {
return dataSource
.filter(function (value) {
return options.indexOf(value) !== -1;
});
})
.switch()
.subscribe(function (x) {
console.log('out: ' + x);
});
使用switch() 假定dataSource 是hot observable。
使用interval() 生成虚拟数据的示例:
var input,
checkedInputValuesSource,
dataSource;
input = document.querySelectorAll('input');
// Generate source describing the current filter.
checkedInputValuesSource = Rx.Observable
.fromEvent(input, 'change')
.map(function () {
var inputs = document.querySelectorAll('input'),
checkedInputValues = [];
[].forEach.call(inputs, function (e) {
if (e.checked) {
checkedInputValues.push(e.value);
}
});
return checkedInputValues;
})
.startWith([]);
// Generate random data source (hot).
dataSource = Rx.Observable
.interval(500)
.map(function () {
var options = ['a', 'b', 'c'];
return options[Math.floor(Math.floor(Math.random() * options.length))];
})
.do(function (x) {
console.log('in: ' + x);
})
.share();
checkedInputValuesSource
.map(function (options) {
return dataSource
.filter(function (value) {
return options.indexOf(value) !== -1;
});
})
.switch()
.subscribe(function (x) {
console.log('out: ' + x);
});
<script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>
<input type='checkbox' value='a'>
<input type='checkbox' value='b'>
<input type='checkbox' value='c'>
此示例将产生类似于以下内容的输出:
in: c
in: a
out: a
in: b
in: c
out: a
in: b
in: a
in 反映所有生成的输入,b 反映通过过滤器的数据。过滤器通过检查复选框输入来调整,反映值“a”、“b”和“c”。
【讨论】:
publish(...)。像这样:dataSource .publish(dsrc => checkedInputValuesSource .switchMap((options) => dsrc .filter((value) => options.indexOf(value) !== -1) ) )
显然,我需要的是 select、filter 和 switchLatest 的组合。我写了一个小测试用例来证明这一点:https://gist.github.com/igstan/d5b8db7b43f49dd87382#file-observable-filter-observable-js-L36-L45
【讨论】:
map 和 filter,我认为它们只是您为 select 和 where 制作的别名?
扩展来自@Dorus 的答案...在 Kotlin 中,您可以这样做:
val observable: Observable<Data> = ...
val filter: Observable<Checkbox> = ...
val filtered: Observable<Data> =
observable.filterWithLatestFrom(filter) { checkbox -> checkbox.isSelected }
使用扩展功能:
/**
* Return an [Observable] with type [T1] that is filtered using the last event emitted by the [other] observable.
*/
fun <T1 : Any, T2 : Any> Observable<T1>.filterWithLatestFrom(other: Observable<T2>, filterFunction: (T2) -> Boolean)
: Observable<T1> {
return this.withLatestFrom(other) { obs1, obs2 -> Pair(obs1, obs2) }
.filter { (_, obs2) -> filterFunction.invoke(obs2) }
.map { (obs1, _) -> obs1}
}
【讨论】: