C# 我可以使用什么运算符返回两个序列的“重叠”?
我有一个流IObservable eventStream,它表示键盘输入skeyup或KeyDown的流。通过应用窗口操作符,我可以隔离保持输入的持续时间:C# 我可以使用什么运算符返回两个序列的“重叠”?,c#,system.reactive,C#,System.reactive,我有一个流IObservable eventStream,它表示键盘输入skeyup或KeyDown的流。通过应用窗口操作符,我可以隔离保持输入的持续时间: public static IObservable<InputEvent> WhileHeld(this IObservable<InputEvent> source, String key) { var k = source.Where(i => i.Key == key); return s
public static IObservable<InputEvent> WhileHeld(this IObservable<InputEvent> source, String key) {
var k = source.Where(i => i.Key == key);
return source.Window(k.Press(), _ => k.Release()).Switch().Where(i => i.Key != key);
}
我想应用一个运算符来查找这两个序列之间的重叠,如下图所示
K=事件类型,其中。是媒体,是发布
i=事件流
C=eventStream.whilheldctrl
S=eventStream.whilheldshift
r=结果流
大理石:
K |--.---.-.-.-'-'---.-.-.-'-'---.-.-'-.-.-.-'
i |--a---C-S-b-S-C---C-S-c-C-S---C-S-S-d-S-e-C-
C |--------S-b-S-------S-c---------S-S-d-S-e---
S |----------b-----------c-C---------------e-C
r |----------b-----------c-----------------e---
是否存在这样的运营商?或者它是如何组成的
编辑:
为了帮助可视化实际事件流,我意识到上面的大理石图有点复杂。以下是我的事件流测试代码:
eventStream.Pump("a", EventType.Down); // should not propagate
eventStream.Pump("ctrl", EventType.Down);
eventStream.Pump("shift", EventType.Down);
eventStream.Pump("b", EventType.Down); // should propagate
eventStream.Pump("shift", EventType.Up);
eventStream.Pump("ctrl", EventType.Up);
eventStream.Pump("ctrl", EventType.Down);
eventStream.Pump("shift", EventType.Down);
eventStream.Pump("c", EventType.Down); // should propagate
eventStream.Pump("ctrl", EventType.Up);
eventStream.Pump("shift", EventType.Up);
eventStream.Pump("ctrl", EventType.Down);
eventStream.Pump("shift", EventType.Down);
eventStream.Pump("shift", EventType.Up);
eventStream.Pump("d", EventType.Down); // should not propagate
eventStream.Pump("shift", EventType.Down);
eventStream.Pump("e", EventType.Down); // should propagate
eventStream.Pump("ctrl", EventType.Up);
到目前为止,我最接近的是:
var ctrlShift = Observable.CombineLatest(ctrlHeld, shiftHeld)
.SelectMany(list =>
{
if (list.Any(o => o != list[0]))
return Observable.Empty<InputEvent>();
else
return Observable.Return(list[0]);
});
它确实有用,但有点难看。如果有比这更简洁、更富有表现力的答案,我会接受它。注:我会在电脑前测试/修改一次 我认为您可以通过GroupJoin获得重叠窗口行为,如下所示:
var ctrlShift = ctrlHeld.GroupJoin(
shiftHeld,
e => eventStream.Key("ctrl").Release(), // "left duration" selector
e => eventStream.Key("shift").Release(), // "right duration" selector
(a,b) => b.Key(a.Key).Press())
.Switch();
但我永远无法单独从视觉上正确理解GroupJoin语法,因此很可能不是这样……基本上,我的想法是:
从ctrlHeld中的事件开始,直到发生ctrl释放
从换档中的事件开始到换档释放发生
选择重叠b,仅按两个窗口中的按钮
将这些嵌套的观测值展平并返回
编辑:进一步考虑,您可能可以在持续时间中重用窗口选择器
var ctrlShift = ctrlHeld.GroupJoin(
shiftHeld,
e => ctrlHeld, // "left duration" selector
e => shiftHeld, // "right duration" selector
(a,b) => b.Key(a.Key).Press())
.Switch();
啊哈,我知道有一个链接解释了这一点:
我最终提出的解决方案提供了x.whilheldctrl.whilheldshift的合成语法。诀窍是传入从原始源派生的IObservable,而不是字符串,然后打开它:
public static IObservable<InputEvent> WhileHeld(this IObservable<InputEvent> source, IObservable<InputEvent> held) {
return source.Window(held.Press(), _ => held.Release()).Switch();
}
...
var x = InputStream.Where(i => i.Key == "X");
var shift = InputStream.Where(i => i.Key == "Shift");
var ctrl = InputStream.Where(i => i.Key == "Ctrl");
// gets all key presses of X while shift and control are held
var ctrlShiftX = x.WhileHeld(shift).WhileHeld(ctrl);
这意味着将捕获按住的键的第一次和最后一次按键,但我认为这不一定是件坏事。您不能只使用r=eventStream.whilheldCtrl.whilheldshift吗?我希望它这么简单!如果有人能想到一个whilehold操作符,它的性能与上面的一样,那么我会接受这一点——遗憾的是,这不起作用——它接受上面的d,当r=eventStream.whileholdshift.whileholdctrl反转为r=eventStream.whileholdshift.whilewaldctrl时,它什么也不接受——那么你大概想要的是如果ctrl+shift+key=>key?我想要问题中描述的行为,我不知道如何解释你的评论…哈-足够公平;我想尝试重新表述您的问题:您希望结果流是在按住shift和control键的同时按下的键?
public static IObservable<InputEvent> WhileHeld(this IObservable<InputEvent> source, IObservable<InputEvent> held) {
return source.Window(held.Press(), _ => held.Release()).Switch();
}
...
var x = InputStream.Where(i => i.Key == "X");
var shift = InputStream.Where(i => i.Key == "Shift");
var ctrl = InputStream.Where(i => i.Key == "Ctrl");
// gets all key presses of X while shift and control are held
var ctrlShiftX = x.WhileHeld(shift).WhileHeld(ctrl);