Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Rx IObservable仅当值发生一定幅度的变化时才产生值_C#_.net_C# 4.0_System.reactive - Fatal编程技术网

C# Rx IObservable仅当值发生一定幅度的变化时才产生值

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,跟踪上次生成的内容,并且只有当值超过上次生成的值的容差级别时

我有一种感觉,这可能是一个非常简单的扩展方法,我错过了,但我找不到它

我基本上想要取一个流,它产生一个流,其中值在每个新值上缓慢递增。我想通过“容忍度”而不是时间来限制/取样。e、 g

当我有像[1,4,20,33]这样的序列时,我想在值的变化超过上一个值的15时输出,这将导致:[1,20]。其中,值12的变化将导致:[1,20,33]

有内置的Rx扩展吗?理想情况下,它可以在所有数字类型上工作,而不为每个类型写入重载。

您可以使用on,跟踪上次生成的内容,并且只有当值超过上次生成的值的容差级别时,谓词才返回true

可以将其包装到一个扩展方法中,该方法利用闭包来实现这一点,如下所示:

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)