关于javascript:使用rxjs按阈值平整数值序列

Flatten sequence of numeric values by threshold with rxjs

使用rxjs,我得到了一个可观察到的浮点数序列。现在,我想过滤出流中较小的变化,并且仅当它比先前发出的值大某个数量时才发出一个值。

换句话说:始终发出序列中的第一个值。然后,每个发出的(=未过滤的)值应至少比先前发出的值大delta。任何不符合该条件的值都将被过滤。

我已经想出了一个解决方案,可以如上所述完成我想要的工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var obs = Rx.Observable.create(function(observer) {
  /* ... */
});

var last;

obs.map(function(value) {
  if (last === undefined) {
    last = value;
    return value;
  } else {
      var threshold = 0.5,
          delta = Math.abs(last - value);

      if (delta > threshold) {
        last = value;
        return value;
      }
      else {
        return undefined;
      }
    }
  }).
  filter(function(value) {
    return value !== undefined;
  });

我是rxjs和反应式编程的新手,我认为上述解决方案过于复杂。更重要的是,它违反了反应式编程的原则,即不将状态保存在组合管道之外。但是我这样做是因为我正在通过last变量跟踪并希望摆脱它。

如何解决此问题并以反应方式进行?


您可以使用scan来管理状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var filtered = obs.scan({}, function (acc, value) {
    if (acc.value !== undefined) {
        var threshold = 0.5,
            change = Math.abs(acc.value - value);

        if (change < threshold) {
            return { value: acc.value, isValid: false };
        }
    }

    return { value: value, isValid: true };
})
.filter(function (acc) { return acc.isValid; })
.map(function (acc) { return acc.value; });

我知道这已经回答了,但是如果您发现自己经常这样做,则可以自己做。只是吐口水,因为它是一个有趣的实用程序:

1
2
3
4
5
6
7
8
9
10
11
12
Observable.prototype.maxThreshold = function(threshold, selector) {
  var last = null;
  return this.filter(function(x) {
    var n = selector ? selector(x) : x;
    var delta = Math.abs(n - last);
    if(last === null || delta > threshold) {
      last = n;
      return true;
    }
    return false;
  });
});

可用于以下用途:

1
2
3
4
streamOfNumbers.maxThreshold(0.5).
  subscribe(function(x) {
    console.log(x);
  });

1
2
3
4
streamOfObjects.maxThreshold(0.5, function(x) { return x.value; }).
  subscribe(function(x) {
    console.log(x);
  });