我想要实现以下结果:
L --1---3---4---5---6---7---8-
R ---A--------B--CDE-FG--H---I
O ---A--------B--C--E---G---H-
---1--------4--5--6---7---H-
所以基本上我有两个相对速度随时间变化的来源。结果应忽略有时L
元素,有时忽略R
元素。如何构建那种RX?
我尝试使用Joins,Sample,WithLatestFrom,Distincts等。但我总是可以忽略来自L
来源但不是R
的某些元素。
我试图在C#中实现它,但任何语言答案都会有所帮助。
答案 0 :(得分:2)
您似乎正在寻找ZipLatest
实施。见Does my "zipLatest" operator already exist?
修改强>:
如果你想要一个实现,而不下载一个库,我认为这样可行:
public static IObservable<Tuple<T1, T2>> ZipLatest<T1, T2>(this IObservable<T1> left, IObservable<T2> right)
{
return Observable.Defer(() =>
{
var leftSubject = new BehaviorSubject<bool>(false);
var rightSubject = new BehaviorSubject<bool>(false);
return left.Publish(_left =>
right.Publish(_right =>
{
return Observable.CombineLatest(
_left,
_right,
_left.Select(_ => true).Merge(leftSubject),
_right.Select(_ => true).Merge(rightSubject),
(l, r, l_bool, r_bool) => Tuple.Create(l_bool, r_bool, l, r)
)
.Where(t => t.Item1 && t.Item2)
.Select(t => Tuple.Create(t.Item3, t.Item4))
.Do(_ =>
{
leftSubject.OnNext(false);
rightSubject.OnNext(false);
});
})
);
});
针对@ Enigmativity的测试代码(已修改)运行...
void Main()
{
var L = new Subject<int>();
var R = new Subject<char>();
var O = L.ZipLatest(R)
.Select(t => new { l = t.Item1, r = t.Item2});
O.Subscribe(o => Console.WriteLine($"{o.l}{o.r}"));
L.OnNext(1);
R.OnNext('A');
L.OnNext(3);
L.OnNext(4);
R.OnNext('B');
L.OnNext(5);
R.OnNext('C');
R.OnNext('D');
R.OnNext('E');
L.OnNext(6);
R.OnNext('F');
R.OnNext('G');
L.OnNext(7);
R.OnNext('H');
L.OnNext(8);
R.OnNext('I');
}
...你得到了正确的结果:
1A
4B
5C
6E
7G
8H
答案 1 :(得分:1)
这是我现在的尝试;我稍后会在编译器中尝试这个!
跟踪通过最新组合发送的最后一个值,并确保在应用操作之前每个值都是唯一的。将此操作定义为扩展方法。
public static IObservable<C> ZipLatest<A, B, C>(
this IObservable<A> sourceA,
IObservable<B> sourceB,
Func<A, B, C> op)
{
IObservable<Tuple<A, B>> combined = sourceA.CombineLatest(
sourceB, (a, b) => Tuple.Create(a, b));
Tuple<A, B> last = null;
return combined.Where(curr =>
{
if (last == null || (last.Item1 != curr.Item1 && last.Item2 != curr.Item2))
{
last = curr;
return true;
}
return false;
}).Select(curr => op(curr.Item1, curr.Item2));
}
答案 2 :(得分:0)
你所要求的似乎没有规则。您需要能够始终如一地描述来自L
和R
的值会发生什么。
这是我能得到的最接近的地方:
var L = new Subject<int>();
var R = new Subject<char>();
var O = L.Select(l => R.Select(r => new { r, l })).Switch();
O.Subscribe(o => Console.WriteLine($"{o.l}{o.r}"));
L.OnNext(1);
R.OnNext('A');
L.OnNext(3);
L.OnNext(4);
R.OnNext('B');
L.OnNext(5);
R.OnNext('C');
R.OnNext('D');
R.OnNext('E');
L.OnNext(6);
R.OnNext('F');
R.OnNext('G');
L.OnNext(7);
R.OnNext('H');
L.OnNext(8);
R.OnNext('I');
那给了我:
1A 4B 5C 5D 5E 6F 6G 7H 8I
此外,从您的大理石图表中,不清楚'F'
或6
是否排在第一位。您需要澄清价值顺序和组合流的规则。