我需要观察一个以固定时间间隔产生值的流,但是产生的值太多了,因此我希望每十个值中取一个。
非响应式编程的等价方式如下:
int step = 10; // take every 10th value
var numbers = Enumerable.Range(0, 100).Where((e, i) => i % step == 0);
在Rx中,最常用的方法是什么?
我需要观察一个以固定时间间隔产生值的流,但是产生的值太多了,因此我希望每十个值中取一个。
非响应式编程的等价方式如下:
int step = 10; // take every 10th value
var numbers = Enumerable.Range(0, 100).Where((e, i) => i % step == 0);
Where
或Buffer
:int step = 10; // take every 10th value
// Where
var numbers = Observable.Range(0, 100).Where((e, i) => i % step == 0);
// Buffer
numbers = Observable.Range(0, 100).Buffer(step).Select(x => x[step - 1]);
我建议避免使用具有 Func<TSource, int, bool> predicate
参数的 Where
运算符,以免因源序列产生超过 2,147,483,647 个元素而导致 OverflowException
异常。无论是 Linq 还是 Rx 运算符都允许算术溢出发生,我不知道任何可防止此情况发生的解决方法。
这里提供了一个名为 TakeEvery
的自定义运算符,在这方面是安全的:
/// <summary>Samples the observable sequence by returning one every N elements,
/// ignoring the other elements.</summary>
public static IObservable<T> TakeEvery<T>(this IObservable<T> source, int step)
{
if (step < 1) throw new ArgumentOutOfRangeException(nameof(step));
return Observable.Defer(() =>
{
int index = -1;
return source.Where(value => (index = ++index % step) == 0);
});
}
Observable.Range(0, 100).Where((value, index) => index % step == 0)
。意思是筛选出从0到99的数字序列中,满足索引值除以给定步长无余数的元素。 - Evk