Momentarily ignore values from Observable when another Observable provides a value

萝らか妹 提交于 2019-12-10 11:04:03

问题


I need to ignore Observable values for a period of time when another Observable provides a value.

Currently, my implementation uses a variable to control blocking (or ignoring).

bool block = false;

var blocker = observable1.Do(_ => block = true )
                         .Throttle( _ => Observable.Timer(_timeToBlock)
                         .Subscribe( _ => block = false ));

var receiver = observable2.Where( i => !block && SomeCondition(i) )
                          .Subscribe( i=> EvenMoreStuff(i) );

Is there a more Rx way to do this, by combining these two observables?

EDIT: small change to blocker subscription


回答1:


The first task is to express your block variables as an observable.

IObservable<bool> blockObservable = observable1
    .Select(x => Observable.Concat(
        Observable.Return(true),
        Observable.Return(false).Delay(_timeToBlock)))
    .Switch()
    .DistinctUntilChanged();

Each time observable1 emits a value, we select an observable that emits true, waits _timeToBlock, then emits false. The Switch just always switches to the most recent of those observables.

Here's a marble diagram. Let's assume that _timeToBlock is 3 characters long.

observable1      -----x--xx-x-----x-----
select0               T--F
select1                  T--F
select2                   T--F
select3                     T--F
select4                           T--F
switch           -----T--TT-T--F--T--F--
blockObservable  -----T--------F--T--F--

Now we can Zip your sequence of values with the MostRecent value of the blockObservable.

var receiverObservable = observable2
    .Zip(blockObservable.MostRecent(false), (value, block) => new { value, block })
    .Where(x => !x.block)
    .Select(x => x.value);



回答2:


As an alternative using disposables you could create a small extension method:

public static IObservable<TResult> Suppress<TResult, TOther>(
                                    this IObservable<TResult> source, 
                                         IObservable<TOther> other,
                                         TimeSpan delayFor)
{
  return Observable.Create<TResult>(observer => {
    var published = source.Publish();
    var connected = new SerialDisposable();
    Func<IDisposable> connect = () => published.Subscribe(observer);
    var suppressor = other.Select(_ => Observable.Timer(delayFor)
                                .Select(_2 => connect())
                                .StartWith(Disposable.Empty))
    .Switch();

    return new CompositeDisposable(
                connected,
                suppressor.StartWith(connect())
                          .Subscribe(d => connected.Disposable = d),
                published.Connect());
  });
}

This will convert the source observable into a ConnectableObservable, then every time the other source emits it will dispose of its subscription, then reconnect when the timer expires.



来源:https://stackoverflow.com/questions/31025784/momentarily-ignore-values-from-observable-when-another-observable-provides-a-val

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!