我希望结合许多IObservable<bool>
个流,这样当所有这些流的最新值为真时,会发出一个true,否则会发出false。
CombinedLast
允许我轻松地为两个流构建类似的东西,但是a)我不确定API是否容易允许组合数千个流b)我不确定它的效率如何即便可能。
All
有点类似于我想要的东西,除了我假设它适用于单个序列而且一旦错误就不能动态地变回真。
此外,我需要将值设置为“直到更改”,尽管DistintUntilChanged
运算符对此可能效率不高?
我希望有一个O(1)算法。
答案 0 :(得分:1)
我不知道如何以经典功能的方式做到这一点,仍然实现O(1)。这使用了可变状态,并且O(1)用于观察每条消息,但O(n)用于记忆:
public IObservable<bool> CombineBooleans(this IObservable<bool>[] source)
{
return source.Select((o, i) => o.Select(b => (value: b, index: i)))
.Merge()
.Scan((array: new bool[source.Length], countFalse: source.Length), (state, item) =>
{
var countFalse = state.countFalse;
if (state.array[item.index] == item.value)
return (state.array, countFalse); //nothing to change, emit same state
else if (state.array[item.index]) //previous/current state is true, becoming false
{
countFalse++;
state.array[item.index] = false;
}
else //previous/current state is false, becoming true
{
countFalse--;
state.array[item.index] = true;
}
return (state.array, countFalse);
})
.Scan((countFalse: source.Length, oldCountFalse: source.Length), (state, item) => (countFalse: item.countFalse, oldCountFalse: state.countFalse))
.SelectMany(state =>
state.countFalse == 1 && state.oldCountFalse == 0
? Observable.Return(false)
: state.countFalse == 0 && state.oldCountFalse == 1
? Observable.Return(true)
: Observable.Empty<bool>()
)
.Publish()
.RefCount();
}
编辑:添加.Publish().Refcount()
以消除多用户错误。
答案 1 :(得分:1)
组合最新版本的好方法是从IObservable<IObservable<T>>
开始,然后将其转换为IObservable<T[]>
。这将成为一种非常动态的方式,可以组合您需要的多个值。
这是执行此操作的扩展方法:
public static IObservable<T[]> CombineLatest<T>(this IObservable<IObservable<T>> sources)
{
return
sources.Publish(ss =>
Observable.Create<T[]>(o =>
{
var composite = new CompositeDisposable();
var list = new List<T>();
composite.Add(
ss.Subscribe(source =>
{
var index = list.Count;
list.Add(default(T));
composite.Add(source.Subscribe(x => list[index] = x));
}));
composite.Add(ss.Merge().Select(x => list.ToArray()).Subscribe(o));
return composite;
}));
}
这很好地创建并跟踪所有订阅,并使用闭包来定义每个订阅需要用来更新其用于输出的index
中的值的list
。
如果你这样使用它:
var sources = new Subject<IObservable<bool>>();
var output = sources.CombineLatest();
output.Subscribe(x => Console.WriteLine(x));
var s1 = new Subject<bool>();
sources.OnNext(s1);
s1.OnNext(true);
var s2 = new Subject<bool>();
sources.OnNext(s2);
s2.OnNext(false);
var s3 = new Subject<bool>();
sources.OnNext(s3);
s3.OnNext(true);
s2.OnNext(true);
s1.OnNext(false);
然后你得到这个输出:
如果您将output
的定义更改为var output = sources.CombineLatest().Select(xs => xs.Aggregate((x, y) => x & y));
,那么您会得到我认为您正在追求的输出:
True False False True False