Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在Rx.NET中组合两个不同的GroupedStreams?_C#_F#_Rx.net - Fatal编程技术网

C# 如何在Rx.NET中组合两个不同的GroupedStreams?

C# 如何在Rx.NET中组合两个不同的GroupedStreams?,c#,f#,rx.net,C#,F#,Rx.net,类似,但不适用于我的情况,因为用户需要合并来自同一IGroupedObservable的可观察流,而我希望合并来自不同组的流 我有以下结构和流程: type A = { Id: int Value: int } type B = { Id: int Value: int } //subjects to test input, just any source of As and Bs let subjectA: Subject<A> = Subject.broadc

类似,但不适用于我的情况,因为用户需要合并来自同一IGroupedObservable的可观察流,而我希望合并来自不同组的流

我有以下结构和流程:

type A = {
  Id: int
  Value: int
}

type B = {
  Id: int
  Value: int
}

//subjects to test input, just any source of As and Bs
let subjectA: Subject<A> = Subject.broadcast
let subjectB: Subject<B> = Subject.broadcast

//grouped streams
let groupedA: IObservable<<IGroupedObservable<int, A>> = Observable.groupBy (fun a -> a.Id) subjectA
let groupedB: IObservable<<IGroupedObservable<int, B>> = Observable.groupBy (fun b -> b.Id) subjectB
A型={
Id:int
值:int
}
B类={
Id:int
值:int
}
//受试者接受测试输入,只是As和Bs的任何来源
让主题a:Subject=Subject.broadcast
让主题B:Subject=Subject.broadcast
//分组流
让组a:IObservable a.Id)subjectA
让groupedB:IObservable b.Id)subjectB
当groupedA.Key=groupedB.Key时,我想以某种方式合并A和B的内部观察值,并得到A.Id=B.Id的(A,B)对的观察值

我想要的签名是这样的
IObservable->IObservable->IObservable
where for all(A,B),A.Id=B.Id

我尝试了一系列CombineTest、groupJoin、filters和maps变体,但没有成功


我正在将F#与Rx.Net和FSharp.Control.Reactive一起使用,但是如果你知道答案是C#(或者任何语言,真的)的话,请先发布它,这有你想要的签名:

let cartesian left right =
    rxquery {
        for a in left do
        for b in right do
        yield a, b
    }

let mergeGroups left right =
    rxquery {
        for (leftGroup : IGroupedObservable<'key, 'a>) in left do
        for (rightGroup : IGroupedObservable<'key, 'b>) in right do
        if leftGroup.Key = rightGroup.Key then
            let merged = cartesian leftGroup rightGroup
            yield {
                new IGroupedObservable<_, _> with
                    member __.Key = leftGroup.Key
                    member __.Subscribe(observer) = merged.Subscribe(observer)
            }
    }
让笛卡尔左向右=
rxquery{
在左边做一个
对b来说正确吗
产量a,b
}
让我们从左向右合并组=
rxquery{
对于左do中的(leftGroup:IGroupedObservable)
对于右do中的(rightGroup:IGroupedObservable)
如果leftGroup.Key=rightGroup.Key,则
设merged=笛卡尔左组右组
屈服{
新的iGroupeObservable与
成员_u.Key=leftGroup.Key
成员订阅(观察员)=合并订阅(观察员)
}
}

然而,在我的测试中,这些组都是空的。我没有足够的Rx经验来了解原因,但也许其他人知道。

这里有一个自定义操作员
GroupJoin
,您可以使用。它基于
选择
合并
分组依据
其中
运算符:

/// <summary>
/// Groups and joins the elements of two observable sequences, based on common keys.
/// </summary>
public static IObservable<(TKey Key, IObservable<TLeft> Left, IObservable<TRight> Right)>
    GroupJoin<TLeft, TRight, TKey>(
    this IObservable<TLeft> left,
    IObservable<TRight> right,
    Func<TLeft, TKey> leftKeySelector,
    Func<TRight, TKey> rightKeySelector,
    IEqualityComparer<TKey> keyComparer = null)
{
    // Arguments validation omitted
    keyComparer ??= EqualityComparer<TKey>.Default;
    return left
        .Select(x => (x, (TRight)default, Type: 1, Key: leftKeySelector(x)))
        .Merge(right.Select(x => ((TLeft)default, x, Type: 2, Key: rightKeySelector(x))))
        .GroupBy(e => e.Key, keyComparer)
        .Select(g => (
            g.Key,
            g.Where(e => e.Type == 1).Select(e => e.Item1),
            g.Where(e => e.Type == 2).Select(e => e.Item2)
        ));
}
//
///基于公共键,对两个可观察序列的元素进行分组和连接。
/// 
公共静态IObservable
团体加入(
这是可以观察到的左边,
可观察到的权利,
Func leftKeySelector,
Func rightKeySelector,
IEqualityComparer键比较器=空)
{
//省略参数验证
keyComparer???=EqualityComparer.Default;
左转
.Select(x=>(x,(TRight)默认值,类型:1,键:leftKeySelector(x)))
.Merge(right.Select(x=>((TLeft)默认值,x,类型:2,键:rightKeySelector(x)))
.GroupBy(e=>e.Key,keycomarer)
.选择(g=>(
g、 钥匙,
g、 其中(e=>e.Type==1)。选择(e=>e.Item1),
g、 其中(e=>e.Type==2)。选择(e=>e.Item2)
));
}
用法示例:

var subjectA = new Subject<A>();
var subjectB = new Subject<B>();

IObservable<IGroupedObservable<int, (A, B)>> query = subjectA
    .GroupJoin(subjectB, a => a.Id, b => b.Id)
    .SelectMany(g => g.Left.Zip(g.Right, (a, b) => (g.Key, a, b)))
    .GroupBy(e => e.Key, e => (e.a, e.b));
var subjectA=新主题();
var subjectB=新主题();
IObservable query=subjectA
.GroupJoin(subjectB,a=>a.Id,b=>b.Id)
.SelectMany(g=>g.Left.Zip(g.Right,(a,b)=>(g.Key,a,b)))
.GroupBy(e=>e.Key,e=>(e.a,e.b));

我不清楚这是否是您想要的。因此,首先用运行程序代码澄清可能会有所帮助。假设运行程序代码如下:

var aSubject = new Subject<A>();
var bSubject = new Subject<B>();

var groupedA = aSubject.GroupBy(a => a.Id);
var groupedB = bSubject.GroupBy(b => b.Id);

//Initiate solution

solution.Merge()
    .Subscribe(t => Console.WriteLine($"(Id = {t.a.Id}, AValue = {t.a.Value}, BValue = {t.b.Value}  )"));

aSubject.OnNext(new A() { Id = 1, Value = 1 });
aSubject.OnNext(new A() { Id = 1, Value = 2 });

bSubject.OnNext(new B() { Id = 1, Value = 10 });
bSubject.OnNext(new B() { Id = 1, Value = 20 });
bSubject.OnNext(new B() { Id = 1, Value = 30 });
如果是这种情况,您可以得到如下解决方案:

var solution = groupedA.Merge()
    .Join(groupedB.Merge(),
        _ => Observable.Never<Unit>(),
        _ => Observable.Never<Unit>(),
        (a, b) => (a, b)
    )
    .Where(t => t.a.Id == t.b.Id)
    .GroupBy(g => g.a.Id);
var solution=groupedA.Merge()
.Join(groupedB.Merge(),
_=>可观察到的。从不(),
_=>可观察到的。从不(),
(a,b)=>(a,b)
)
.其中(t=>t.a.Id==t.b.Id)
.GroupBy(g=>g.a.Id);

我要提醒大家,如果这是一个长期运行的过程的一部分,这里会对内存/性能产生影响。这会将所有
A
B
对象无限期地保留在内存中,等待它们是否可以配对。要缩短它们在内存中的保留时间,请将
Observable.Never()
调用更改为适当的窗口,使每个对象在内存中保留多长时间。

是否要完全交叉联接?唯一的要求是a.Id==b.Id?我不确定“完全交叉连接”在这个上下文中的含义,但我相信是的。我认为
可观察。groupBy
返回一个
IObservable
,而不仅仅是一个
IGroupedObservable
,所以我假设这就是您实际试图组合的内容?@brianberns正确,修复了它。是的,这就是我想要实现的。在我的例子中,我想将Id=1的最新A与Id=1的最新B进行匹配,而Id=1的A和B的旧值可以从内存中释放出来。我该怎么做?我不太明白这个观察到的是什么。我认为从来没有这样做过。@fnzr这是重要的信息,可能应该包括在问题中。你能回答这个问题并把这个信息添加到那里吗?
var solution = groupedA.Merge()
    .Join(groupedB.Merge(),
        _ => Observable.Never<Unit>(),
        _ => Observable.Never<Unit>(),
        (a, b) => (a, b)
    )
    .Where(t => t.a.Id == t.b.Id)
    .GroupBy(g => g.a.Id);