在rxjs上找到数组元素交集的最佳方法是什么



我知道JavaScriptArray上有includes运算符

因此,从另外两个数组中查找公共元素是没有问题的。(https://stackoverflow.com/a/1885569/11455650)

那么,在rxjs上实现这一点的最佳方式是什么?

const obs1$ = from(["foo", "bar", "baz", "qux"]);
const obs2$ = from(["bar", "garply", "fred", "foo"];
// const commonIntersection$ = functions or operators...
// result must be ["foo", "bar"]

我认为有两种方法可以实现这一点。

哪一个是计算高效的?我如何使用rxjs运算符实现这一点?

  1. merge两个数组,只发射第二个值(忽略第一个值(
  2. filter每个元素

我想你希望每个排放都有一个运行的十字路口?如果是这样,您可以使用扫描运算符,也可以滚动您自己的特定交叉点操作符。

scan运算符类似于数组上的reduce方法。在这种情况下,对于每个元素(它是一个字符串数组(,都会返回交集。接下来的每一次发射都将对最后的结果起作用。

merge(from([["foo", "bar", "baz", "qux"], ["bar", "garply", "fred", "foo"]])).pipe(
map(x => x),
scan((acc, cur) => {
return (!acc) 
? next
: acc.filter(x => cur.includes(x));
}, undefined as string[] | undefined),
).subscribe(x => console.log(x));

自定义操作符看起来会更干净,所以如果你多次需要它,那就去用吧!正如您所看到的,下面的逻辑与扫描版本基本相同。它在acc变量中跟踪运行交叉口状态,并使用current数组对其进行更新。

merge(from([["foo", "bar", "baz", "qux"], ["bar", "garply", "fred", "foo"]])).pipe(
map(x => x),
intersection(),
).subscribe(x => console.log(x));
/*...*/
function intersection<T>(): OperatorFunction<T[], T[]> {
return (observable: Observable<T[]>) => {
return new Observable<T[]>((subscriber) => {
let acc: T[] | undefined; // keeps track of the state.
const subscription = observable.subscribe({
next: (cur) => {
acc = (!acc) 
? cur
: acc.filter(x => cur.includes(x));
subscriber.next(acc);
},
error: (err) => subscriber.error(err),
complete: () => subscriber.complete(),
});
return () => subscription.unsubscribe();
})
}
}

如果您只想要最后一个结果,则将scan运算符更改为reduce,或者在运算符版本的内部订阅的完整回调中仅发出acc的值。

import { forkJoin, from } from 'rxjs';
import { toArray } from 'rxjs/operators';
import { intersection } from 'lodash';
const obs1$ = from(['foo', 'bar', 'baz', 'qux']);
const obs2$ = from(['bar', 'garply', 'fred', 'foo']);
forkJoin([obs1$.pipe(toArray()), obs2$.pipe(toArray())]).subscribe(
([arr1, arr2]) => console.log(intersection(arr1, arr2))
);

请在此处尝试:https://stackblitz.com/edit/rxjs-6jdyzy?file=index.ts

这不是rxjs使用的代码,而是使用JavaScript本机数组方法(过滤器包括(。

它似乎比rxjs运算符更快。

const intersectionArray = combineLatest({
firstArray: [["foo", "bar", "baz", "qux"]],
secondArray: [["bar", "garply", "fred", "foo"]],
}).pipe(
map((x) => x.firstArray.filter((value) => x.secondArray.includes(value)))
);
intersectionArray.subscribe(console.log);

相关内容

最新更新