Фильтр на основе последних прошлых сообщений других наблюдаемых - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь отфильтровать сообщения из наблюдаемой на основе сообщений другой наблюдаемой.

navCmds          --A----B---C--A------D-----------------C-----D----E--->

navNotifications ----A----X---B-C-A---D------------------------DCA---E->

result           ---------X--------------------------------------A----->

В моей программе я отправляю команды навигации во внешнее приложение.
Приложение уведомляет меняиз каких экранов он изменился.
Уведомления могут быть связаны с тем, что я отправил команду навигации, а также с тем, что пользователь перемещался в самом приложении.
Я хочу получить поток только с командами навигации, которые не являются результатом.сообщений, которые я отправил.

Поскольку другое приложение не находится под моим контролем, я не могу расширять сообщения с помощью идентификатора корреляции или другого нового поля.

То, как я думал об этом

  • создание окон в navCmds
  • фильтрация navNotifications в последнем окне

Уведомленияэто не прямой ответ для команды, но WERE, отправленный как cmd ранее в окне, будет потерян.Это приемлемый компромисс.

const notificationsStopped$ = this.navCmds$.pipe(debounceTime(500));
const cmdWindows$ = this.navCmds$.pipe(windowOperator(notificationsStopped$));

const result$ = this.navNotifications$.pipe(
    withLatestFrom(cmdWindows$),
    filter(([notification, pastCmds$]) => // How to filter here?)
);      

Есть ли более простой способ?
Как мне выполнить фильтрацию?

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Если я правильно понял вашу проблему, я бы немного изменил мраморные диаграммы , которые вы предложили для вашей проблемы.

В частности, я бы изменил последнюю DCA последовательность navNotifications на CDA, чтобы отразить тот факт, что в последовательности navCmds сначала вы отправляете C, а затем D,Это означает, что мраморные диаграммы будут выглядеть следующим образом

navCmds          --A----B---C--A------D-----------------C-----D----E--->

navNotifications ----A----X---B-C-A---D------------------------CDA---E->

result           ---------X--------------------------------------A----->

Предполагая, что это правильно, что должно быть подтверждено, вы можете рассмотреть решение по этим направлениям

const queue = new Array<any>();

navCmds$.pipe(
  tap(cmd => queue.push(cmd)),
  switchMap(() => {
    return navNotifications$.pipe(
      switchMap(notification => {
        const cmdFromQueue = queue[0];
        if (notification === cmdFromQueue) {
          queue.shift();
          return empty();
        } else {
          return of(notification);
        }
      })
    )
  })
)

Идея здесь заключается в том, чтобы сначала

  • создать queue, в котором вы сохраняете отправленные команды
  • каждый раз, когда navCmds$ отправляет новую команду, значение равнонажмите queue и поток переключится на navNotifications$, который проверяет queue и выдает notification, если он отличается от последней обработанной команды

Это решение требует состояние должно поддерживаться с помощью переменной queue, но это можно скрыть с помощью пользовательских конвейерных операторов.

Эти решения были протестированы со следующими тестовыми данными

const navCmds$ = new Subject<any>();
setTimeout(() => {navCmds$.next('A')}, 30);
setTimeout(() => {navCmds$.next('B')}, 80);
setTimeout(() => {navCmds$.next('C')}, 120);
setTimeout(() => {navCmds$.next('A')}, 150);
setTimeout(() => {navCmds$.next('D')}, 220);
setTimeout(() => {navCmds$.next('C1')}, 320);
setTimeout(() => {navCmds$.next('D1')}, 380);
setTimeout(() => {navCmds$.next('E')}, 430);


const navNotifications$ = new Subject<any>();
setTimeout(() => {navNotifications$.next('A')}, 50);
setTimeout(() => {navNotifications$.next('X1')}, 100);
setTimeout(() => {navNotifications$.next('X2')}, 110);
setTimeout(() => {navNotifications$.next('B')}, 130);
setTimeout(() => {navNotifications$.next('Y1')}, 140);
setTimeout(() => {navNotifications$.next('Y2')}, 150);
setTimeout(() => {navNotifications$.next('C')}, 160);
setTimeout(() => {navNotifications$.next('A')}, 180);
setTimeout(() => {navNotifications$.next('D')}, 230); // slightly delayed
setTimeout(() => {navNotifications$.next('C1')}, 390); // inverted
setTimeout(() => {navNotifications$.next('D1')}, 400); // inverted
setTimeout(() => {navNotifications$.next('A1')}, 410);
setTimeout(() => {navNotifications$.next('A2')}, 420);
setTimeout(() => {navNotifications$.next('A3')}, 440);
setTimeout(() => {navNotifications$.next('E')}, 460);
0 голосов
/ 23 октября 2018

Чтобы отфильтровать navNotifications по navCmds - мы хотим собрать все navCmds с scan.

- Уменьшить со временем.

Мы предполагаем, что pastCmd является сериализуемым, чтобы поместить его в объект.Также Map можно использовать, так как он может использовать ссылку в качестве ключа

const allPastCmds$ = pastCmds$.pipe(scan(acc, cur)=>({...acc, [cur]: true}),{});

notificationExist проверить, если notification in allPastCmds

filter(([notification, allPastCmds]) => !notificationExist(notification, allPastCmds)
...