C# 基于开始/结束事件对反应流中的事件进行分组
我观察到一个反应流C# 基于开始/结束事件对反应流中的事件进行分组,c#,system.reactive,reactive,C#,System.reactive,Reactive,我观察到一个反应流可观察的,目前它直接发出事件。基于开始/结束事件,我希望在内部组的支持下对事件流进行分组 输入流 我有一系列类似以下的事件: Event(type = Data, groupId = 1) Event(type = BeginGroup, groupId = 2) // outer group begins Event(type = Data, groupId = 2) Event(type = BeginGroup, groupId = 3) // inner gro
可观察的,目前它直接发出事件。基于开始/结束事件,我希望在内部组的支持下对事件流进行分组
输入流
我有一系列类似以下的事件:
Event(type = Data, groupId = 1)
Event(type = BeginGroup, groupId = 2) // outer group begins
Event(type = Data, groupId = 2)
Event(type = BeginGroup, groupId = 3) // inner group begins
Event(type = Data, groupId = 3)
Event(type = EndGroup, groupId = 3) // inner group ends
Event(type = EndGroup, groupId = 2) // outer group ends
Event(type = Data, groupId = 4)
Event(type = Data, groupId = 5)
编辑-其他先决条件:
我在示例数据中添加了ID,但通常不需要ID。该流程将注意满足以下要求:
Event(type = Data, groupId = 1)
Event(type = BeginGroup, groupId = 2) // outer group begins
Event(type = Data, groupId = 2)
Event(type = BeginGroup, groupId = 3) // inner group begins
Event(type = Data, groupId = 3)
Event(type = EndGroup, groupId = 3) // inner group ends
Event(type = EndGroup, groupId = 2) // outer group ends
Event(type = Data, groupId = 4)
Event(type = Data, groupId = 5)
- 每个
BeginGroup
事件将在某个时间后跟相应的EndGroup
事件
- 组内的事件(在我的示例中,具有相同的组思想)将始终位于流内的开始/结束事件内,因此顺序是有保证的(如上面的示例中所示)
所需的输出流
因此,我确保每个事件都是它上面的组的一部分,或者如果它不是真实组的一部分,则具有唯一的id。我想将上述9个事件流分为以下4个事件流:
Event(type = Data, groupId = 1)
GroupEvent(groupId = 2, data = <LIST of Events and/or sub groups>) with following data:
data = [
Event(type = BeginGroup, groupId = 2)
Event(type = Data, groupId = 2)
GroupEvent(groupId = 3, data = <LIST of Events and/or sub groups>) with following data:
data = [
Event(type = BeginGroup, groupId = 3)
Event(type = Data, groupId = 3)
Event(type = EndGroup, groupId = 3)
]
Event(type = EndGroup, groupId = 2)
]
Event(type = Data, groupId = 4)
Event(type = Data, groupId = 5)
这种方法不起作用,它根本不会发出任何东西(不过,eventObservable
确实正确地发出了它的项)。此外,它还失去了嵌套组的支持(理论上,如果它可以工作的话)
有人能给我解释一下如何解决我的问题吗?先转储代码,然后再解释
我写的数据类:
public enum EventType
{
Data,
BeginGroup,
EndGroup,
Group
}
public class Event<T>
{
public Event(int id, EventType type, T data)
{
this.Id = id;
this.Type = type;
this.Data = data;
}
public int Id { get; set; }
public EventType Type { get; set; }
public T Data { get; set;}
}
public class GroupEvent<T> : Event<T> {
public GroupEvent(int id, IEnumerable<Event<T>> events)
: base(id, EventType.Group, default(T))
{
this.ChildData = events;
}
public IEnumerable<Event<T>> ChildData { get; set; }
}
以下是跑步者代码:
var s = new Subject<Event<int>>();
var o = s.GroupEvents();
s.OnNext(new Event<int>(-1, EventType.Data, 1));
s.OnNext(new Event<int>(-1, EventType.BeginGroup, 2));
s.OnNext(new Event<int>(-1, EventType.Data, 3));
s.OnNext(new Event<int>(-1, EventType.BeginGroup, 4));
s.OnNext(new Event<int>(-1, EventType.Data, 5));
s.OnNext(new Event<int>(-1, EventType.EndGroup, 6));
s.OnNext(new Event<int>(-1, EventType.EndGroup, 7));
s.OnNext(new Event<int>(-1, EventType.Data, 8));
s.OnNext(new Event<int>(-1, EventType.Data, 9));
var s=新主题();
var o=s.GroupEvents();
s、 OnNext(新事件(-1,EventType.Data,1));
s、 OnNext(新事件(-1,EventType.BeginGroup,2));
s、 OnNext(新事件(-1,EventType.Data,3));
s、 OnNext(新事件(-1,EventType.BeginGroup,4));
s、 OnNext(新事件(-1,EventType.Data,5));
s、 OnNext(新事件(-1,EventType.EndGroup,6));
s、 OnNext(新事件(-1,EventType.EndGroup,7));
s、 OnNext(新事件(-1,EventType.Data,8));
s、 OnNext(新事件(-1,EventType.Data,9));
结果看起来像你在问题中所期望的
说明:
我采用了状态机方法,这通常意味着使用.Scan
方法。我们在这里的状态是正在运行的groupId
count,以及消息列表的堆栈。堆栈的顶部表示我们当前要将消息添加到的组。由于Scan
不允许您区分状态和输出,我们的第三个状态值是一个输出变量
我使用的是不可变的集合,因为它们在Rx上表现得最好。如果您使用可变集合,性能可以提高,但您必须小心多重订阅影响
至于使用内置操作符(GroupBy
,Buffer
,Window
,Join
,等等),我认为这些操作符中的任何一个都不能很好地与您想要的树状递归结构配合使用。如果您可以使用更平坦的结构,那么Window
可能会起作用,但这需要一些工作。是否希望完全基于顺序/嵌套进行分组?还是按组id?如果id不同步或顺序不正确怎么办?实际上,组id是不相关的,甚至可能不是必需的,事件的顺序可以被认为是理所当然的,并且是分组的来源。因此,我想按顺序分组,并根据事件(关于内部组)启动组/结束组-将此信息添加到我的问题末尾的第一个标题下(实际上,在我的测试中,我甚至在缓冲区(2,1)的帮助下手动添加了GroupId)
并手动生成ID,然后再次将流展平…)非常感谢您的帮助。我认为可能有一个解决方案与窗口操作员,但您的“手动”解决方案看起来相当好,以及完全符合我想要的-谢谢
var s = new Subject<Event<int>>();
var o = s.GroupEvents();
s.OnNext(new Event<int>(-1, EventType.Data, 1));
s.OnNext(new Event<int>(-1, EventType.BeginGroup, 2));
s.OnNext(new Event<int>(-1, EventType.Data, 3));
s.OnNext(new Event<int>(-1, EventType.BeginGroup, 4));
s.OnNext(new Event<int>(-1, EventType.Data, 5));
s.OnNext(new Event<int>(-1, EventType.EndGroup, 6));
s.OnNext(new Event<int>(-1, EventType.EndGroup, 7));
s.OnNext(new Event<int>(-1, EventType.Data, 8));
s.OnNext(new Event<int>(-1, EventType.Data, 9));