Как я могу накапливать количество вхождений каждого значения с течением времени? - PullRequest
1 голос
/ 03 августа 2020

Требование

Дан поток букв: 'a', 'a', 'b', 'b', 'b', 'c'

Вывести следующий вывод, который представляет собой промежуточную сумму количества появлений каждой буквы, встреченной на данный момент:

[{ letter: 'a', count : 1 }]
[{ letter: 'a', count : 2 }]
[{ letter: 'a', count : 2 }, { letter: 'b', count : 1 }]
[{ letter: 'a', count : 2 }, { letter: 'b', count : 2 }]
[{ letter: 'a', count : 2 }, { letter: 'b', count : 3 }]
[{ letter: 'a', count : 2 }, { letter: 'b', count : 3 }, { letter: 'c', count : 1 }]

Возможное решение # 1

Похож на { ссылка } - изначально я пробовал что-то подобное, но подумал, что это не очень похоже на «rx js». Если взглянуть на это еще раз в свете решения №2, это намного проще и вполне может быть способом go.

Возможное решение №2

Частичная попытка : https://stackblitz.com/edit/so-accumulated-letters На основе { ссылка } Он работает до тех пор, пока выводит счетчик отдельных букв по мере их появления ie:

{ letter: 'a', count : 1 }
{ letter: 'a', count : 2 }
{ letter: 'b', count : 1 }
{ letter: 'b', count : 2 }
{ letter: 'b', count : 3 }
{ letter: 'c', count : 1 }

Однако он не отслеживает другие предыдущие буквы. Я пробовал использовать другой scan, combineAll, et c

  1. Следует ли мне использовать подход в решении №1 или №2?
  2. Если №2, как Могу ли я получить его для накопления количества других букв?

Спасибо

1 Ответ

1 голос
/ 04 августа 2020

Попробуйте это:

    const source = ['a', 'b', 'a', 'c', 'd', 'b', 'a'];
    interval(1000)
      .pipe(
        take(7),
        map(i => source[i]),
        groupBy(e => e),
        mergeMap(group => {
          let i = 1;
          return group.pipe(map(e => ({letter: group.key, count: i++})))
        }),
        scan((acc, current) => {
          const index = acc.findIndex(item => item.letter === current.letter);
          if(index > -1) {
            acc[index] = current;
          } else {
            acc.push(current);
          }
          return acc;
        }, [])
      )
      .subscribe(x => console.log(...x))

Demo-1

ОБНОВЛЕНИЕ

Другое простое решение - использовать только map и scan:

source
  .pipe(
    map(e => ({letter: e, count: 1})),
    scan((acc, current) => {
      const index = acc.findIndex(item => item.letter === current.letter);
      if(index > -1) {
        acc[index].count++;
      } else {
        acc.push(current);
      }
      return acc;
    }, [])
  )
  .subscribe(x => console.log(x))

Demo-2

...