如果我有可观察的a
和b
,我想根据第三个可观察的c
在两者之间交替,我将如何做到这一点?大理石图看起来像这样:
a: -a1---------a2----a3--a4------a5--a6-----a7----
b: -b1--b2----b3--b4----------------b5---b6---b7--
c: --------c-----------c--------c----------c------
alternate
-a1--------b3--b4-----a4---------b5---b6-a7----
答案 0 :(得分:3)
这很好用:
var query =
a.Publish(pa =>
b.Publish(pb =>
c.StartWith("c")
.Select((x, n) => n % 2 == 0 ? pa : pb)
.Switch()));
我使用此代码进行了测试:
var xs = new []
{
"a1", "b1", "b2", "c", "b3",
"a2", "b4", "a3", "c", "a4",
"c", "a5", "b5", "a6", "b6",
"c", "a7", "b7",
}
.ToObservable()
.Publish();
var a = xs.Where(x => x.StartsWith("a"));
var b = xs.Where(x => x.StartsWith("b"));
var c = xs.Where(x => x.StartsWith("c"));
var query = ...
query.Subscribe(Console.WriteLine);
xs.Connect();
我得到了这个结果:
a1
b3
b4
a4
b5
b6
a7
仅xs.Connect()
才能使xs
可观察的工作成为生成三个序列的简便方法。
甚至作为扩展方法:
public static IObservable<TSource> Alternate<TSource>(
this IObservable<TSource> leftSelector,
bool startLeft,
IObservable<TSource> left,
IObservable<TSource> right)
{
return
left.Publish(pl =>
right.Publish(pr =>
leftSelector.StartWith(default(TSource))
.Select((x, n) => (n % 2 == (startLeft ? 0 : 1)) ? pl : pr)
.Switch()));
}
答案 1 :(得分:2)
这是另一种方式,类似的想法 - 它还允许您指定选择器的起始值。
关键的想法是使用Zip
和MostRecent
使用最新的选择器值压缩每个值流。然后我们可以根据选择器值过滤每个压缩流并合并它们。
public static IObservable<TSource> Alternate<TSource>(
this IObservable<bool> leftSelector,
bool startLeft,
IObservable<TSource> left,
IObservable<TSource> right)
{
return leftSelector.Publish(
selector =>
Observable.Merge(
left.Zip(selector.MostRecent(startLeft), Tuple.Create)
.Where(l => l.Item2),
right.Zip(selector.MostRecent(startLeft), Tuple.Create)
.Where(r => !r.Item2)))
.Select(res => res.Item1);
}
此外,这里的Enigmativity的整洁方法略微调整,以适应这里的输入:
public static IObservable<TSource> Alternate2<TSource>(
this IObservable<bool> leftSelector,
bool startLeft,
IObservable<TSource> left,
IObservable<TSource> right)
{
return
left.Publish(l =>
right.Publish(r =>
leftSelector.StartWith(startLeft)
.Select(s => s ? l : r)
.Switch()));
}
答案 2 :(得分:1)
此解决方案将c声明为Observable<bool>
结果Observable
根据c的最新值从a和b发出值。 a和b中的值包装在Merge
var a = Observable.Range(1, 10);
var b = Observable.Range(10, 20);
var merged = a.Select(i => new Container {id = "a", value = i})
.Merge( b.Select(i => new Container {id = "b", value = i}));
var c = Observable.Return(true);
var result = merged.CombineLatest( c , (ab, selector )
=> (selector && ab.id == "a") || (!selector && ab.id == "b") ? ab : null)
.Where(i => i != null);
public class Container
{
public string id;
public int value;
}