给定2个热点可观察量t1和t2我将如何获得GoupJoin以便从t2中获得所有事件,这些事件发生在t1中每个事件之后x秒和之后的y秒?
假设:
t1 ----- A ----- B ----- C
t2 --1--2--3--4--5--6
如果t1相隔2秒且t2相隔1秒,我们正在寻找每个t1事件两侧1秒的t2事件,结果如下。
结果:
{A,[1,2,3]}
{B,[3,4,5]}
{C,[5,6]}
以下是真实的例子,我们需要针对上述问题的解决方案。 我们有一组电子邮件和另一组短信。我们需要发出另一个流的结果,其中包含电子邮件,并且在电子邮件发送时间的1分钟之前或之后发生文本消息。
答案 0 :(得分:1)
代码转储答案(使用100毫秒代替1秒):
var t1 = Observable.Interval(TimeSpan.FromMilliseconds(200))
.Select(l => (char)('A' + l))
.Delay(TimeSpan.FromMilliseconds(200));
var t2 = Observable.Interval(TimeSpan.FromMilliseconds(100))
.Delay(TimeSpan.FromMilliseconds(100));
var x = TimeSpan.FromMilliseconds(100); //before time
var y = TimeSpan.FromMilliseconds(100); //after time
var g = t1.Timestamp().Join(t2.Timestamp(),
c => Observable.Timer(y),
i => Observable.Timer(x + y),
(c, i) => new {GroupItem = c, RightItem = i}
)
.Where(a =>
(a.GroupItem.Timestamp > a.RightItem.Timestamp && a.GroupItem.Timestamp - a.RightItem.Timestamp <= x) //group-item came first
|| (a.GroupItem.Timestamp <= a.RightItem.Timestamp && a.RightItem.Timestamp - a.GroupItem.Timestamp <= y) // right-item came first, or exact timestamp match
)
.Select(a => new { GroupItem = a.GroupItem.Value, RightItem = a.RightItem.Value })
.GroupBy(a => a.GroupItem, a => a.RightItem);
说明: Join
完全是关于“windows”的。因此,当您定义连接时,您必须考虑左侧可观察和右侧可观察的每个项目的打开时间窗口。我们这里的窗口很难弄清楚:我们必须以某种方式打开一个窗口,在它发生之前左侧可观察的X时间,然后在它发生之后关闭它。
而不是做不可能的事情,所以我们让它只在左项目发生后打开Y时间,并让右项目窗口由X + Y时间定义。但是,这将为我们留下不应包含的项目。因此,我们在时间戳上使用Where
来过滤掉这些内容。
最后,我们选择匿名类型和时间戳并将它们组合在一起。
我不认为GroupJoin
是这样的方式:你最终会拆开小组并重新组合它,类似于我所做的......
答案 1 :(得分:1)
这里的问题(如Shlomo所提到的)是我们需要在发生t2
事件之前在t1
中打开窗口。不幸的是,这是不可能的,因为一旦我们在t1
中达到了这个事件,我们已经超越了我们需要在t2
打开窗口的时间点。
我们可以做的是使用Delay()及时转移t2
。如果我们将其偏移x
(之前的时间),我们可以将问题重新设置为“t2
中的t1
中的事件,并在t1 + x + y
开始关闭var scheduler = new HistoricalScheduler();
var t1 = Observable.Interval(TimeSpan.FromMilliseconds(200), scheduler)
.Select(l => (char)('A' + l));
var t2 = Observable.Interval(TimeSpan.FromMilliseconds(100), scheduler);
var x = TimeSpan.FromMilliseconds(100); //before time
var y = TimeSpan.FromMilliseconds(100); //after time
var delayedT2 = t2.Delay(x, scheduler);
var g = t1.GroupJoin(delayedT2 ,
_ => Observable.Timer(x + y, scheduler),
_ => Observable.Empty<Unit>(scheduler),
(a, b) => new { a, b}
);
scheduler.Start();
我们可以使用GroupJoin来解决这个问题。
{ A, [1,2] }
{ B, [3,4] }
{ C, [5,6] }
这给出了结果:
t2
这个结果仍然不是你所期待的。这是因为在您的示例中,t1
事件发生在完全相同的即时t1 + y
事件中。在这种情况下,首先处理t2
事件并关闭窗口,然后才能包含(t1-01:00) <= t1 < (t1 + 01:00)
事件。这意味着我们有效地获得了A
。例如。 3
的窗口是01:0000 - 02.9999 ...这就是为什么不包括{03}在03:00发生的原因。
只需在我们的y
时间内添加一个勾号
var y = TimeSpan.FromMilliseconds(100).Add(TimeSpan.FromTicks(1));