C# Rx IObservable仅当值发生一定幅度的变化时才产生值
我有一种感觉,这可能是一个非常简单的扩展方法,我错过了,但我找不到它 我基本上想要取一个流,它产生一个流,其中值在每个新值上缓慢递增。我想通过“容忍度”而不是时间来限制/取样。e、 g 当我有像[1,4,20,33]这样的序列时,我想在值的变化超过上一个值的15时输出,这将导致:[1,20]。其中,值12的变化将导致:[1,20,33] 有内置的Rx扩展吗?理想情况下,它可以在所有数字类型上工作,而不为每个类型写入重载。您可以使用on,跟踪上次生成的内容,并且只有当值超过上次生成的值的容差级别时,谓词才返回true 可以将其包装到一个扩展方法中,该方法利用闭包来实现这一点,如下所示:C# Rx IObservable仅当值发生一定幅度的变化时才产生值,c#,.net,c#-4.0,system.reactive,C#,.net,C# 4.0,System.reactive,我有一种感觉,这可能是一个非常简单的扩展方法,我错过了,但我找不到它 我基本上想要取一个流,它产生一个流,其中值在每个新值上缓慢递增。我想通过“容忍度”而不是时间来限制/取样。e、 g 当我有像[1,4,20,33]这样的序列时,我想在值的变化超过上一个值的15时输出,这将导致:[1,20]。其中,值12的变化将导致:[1,20,33] 有内置的Rx扩展吗?理想情况下,它可以在所有数字类型上工作,而不为每个类型写入重载。您可以使用on,跟踪上次生成的内容,并且只有当值超过上次生成的值的容差级别时
public static IObservable<int> WhenLastObservedChangesByMoreThan(
this IObservable<int> observable, int tolerance)
{
// Validate parameters.
if (observable == null) throw new ArgumentNullException("observable");
// Tolerance must be positive, so comparisons are correct after
// addition/subtraction.
if (tolerance < 0)
throw new ArgumentOutOfRangeExeption("tolerance", tolerance,
"The tolerance parameter must be a non-negative number.");
// Shortcut: If tolerance is 0, then every value is returned, just
// return the observable.
if (tolerance == 0) return observable;
// The last value yielded.
int? lastYielded = null;
// Filter.
observable = observable.Where(i => {
// If there is a previous value
// that was yielded.
if (lastYielded != null)
{
// Is the last value within
// tolerance?
if (i - tolerance < i && i < i + tolerance)
{
// Do not process.
return false;
}
}
// This is being yielded, store the value.
lastYielded = i;
// Yield the value.
return true;
});
}
public static IObservable when last observed changes bymorthan(
这是可观察到的,int公差)
{
//验证参数。
如果(observable==null)抛出新ArgumentNullException(“observable”);
//公差必须为正,因此在测量后比较是正确的
//加减法。
if(公差<0)
把新的论点扔出范围解释(“宽容”,宽容,
“公差参数必须是非负数。”);
//快捷方式:如果公差为0,则返回每个值,只需
//返回可观察的。
如果(公差==0)返回可观察值;
//最后的价值产生了。
int?last=null;
//过滤器。
可观察=可观察。其中(i=>{
//如果有以前的值
//这是让步。
if(lastGendered!=null)
{
//中的最后一个值是
//宽容?
if(i-公差
请注意,上面的操作不是线程安全的,如果您的
IObservable
是从多个线程调用的,那么您必须锁定对lastGendered
变量的访问权限(这很容易用a实现)。另一个可以重新调整用途的内置操作符是,它将为您跟踪最后的值。这里最大的“黑客”是,IEqualityComparer
可能不遵循平等的标准期望(a==b&&b==c
并不意味着a==c
,具体取决于函数)
public static IObservable distinctuntillchangedby(
此IObservable源,Func已更改)
{
//检查参数
返回source.DistinctUntilChanged(新的MarginEqualityComparer(isChanged));
}
类别MarginEqualityComparer:IEqualityComparer
{
边际质量比较程序(功能比较程序)
{
_比较器=比较器;
}
专用只读函数比较器;
公共布尔等于(TX,TY)
{
返回比较器(x,y);
}
公共int GetHashCode(T obj)
{
抛出新的NotSupportedException(“此比较器不支持哈希”);
}
}
我认为这非常适合可观察。扫描
var ob = Enumerable.Range(0, 30).ToObservable();
var largeMovingOb = ob.Scan((acc, i) => acc + 10 > i ? acc : i)
.DistinctUntilChanged();
有一个内置的运营商,你想做什么
试试这个:
var ob = Observable.Range(0, 30);
var largeMovingOb = ob.DistinctUntilChanged(x => x / 10);
它适用于任何类型,而不仅仅是数字类型,因为签名如下所示:
IObservable<TSource> DistinctUntilChanged<TSource, TKey>(
this IObservable<TSource> source, Func<TSource, TKey> keySelector)
IObservable DistinctUntilChanged(
此IObservable源(Func键选择器)
很简单。所以您想要一个仅当值变化超过X时才触发的可观测值?是的,但不仅仅是源生成的最后一个值,而是最后生成的值。见下面对@jeroenh的评论。你知道你可以做var ob=Observable.Range(0,30)代码>?谢谢你的神秘。我一点也不知道;优雅的解决方案,满足规范要求,没有难看的缺陷。虽然示例假设值从0开始递增1,但您的解决方案仅适用于这种情况。如果存在大于1的跳过或种子值不是0,则此操作将不起作用。
var ob = Observable.Range(0, 30);
var largeMovingOb = ob.DistinctUntilChanged(x => x / 10);
IObservable<TSource> DistinctUntilChanged<TSource, TKey>(
this IObservable<TSource> source, Func<TSource, TKey> keySelector)