Rx Intersect运算符

时间:2012-04-02 21:33:22

标签: system.reactive

我从最简单的问题开始我的问题部分是否有可用的Rx Intersect运算符的实现?

基本上我有两个会产生价值的流。 假设流1产生:A,B,C,D,E,F,G 并且流2产生:B,D,F

两个流都将完成且不是无限的(对于后台:它们由我们同时查询的两个不同数据源提供。)

有没有人对如何在Rx世界中实现异步交叉运算符有任何建议?

3 个答案:

答案 0 :(得分:4)

这是一个适用于热观察的不同实现,它为你提供了一个集交集,所以如果'c'在两个流中出现三次,它只会在交叉流中出现一次。

IObservable<char> stream1;
IObservable<char> stream2;

var intersect = Observable
  .Merge(stream1.Distinct(), stream2.Distinct())
  .GroupBy(c=>c)
  .SelectMany(g=>g.Skip(1).Take(1));

示例:

stream1    ---a---b--c--d--e--a-b-c
stream2    -b---a---e---------a-b-c
intersect  -----a-b--------e------c

答案 1 :(得分:3)

据我所知,没有“正式”实施。大多数情况下,您需要从两个来源收集值来存储和检查相反来源中的匹配项。这样的事情应该让你开始:

<Extension()> 
Public Function Intersect(Of T)(first As IObservable(Of T), 
                                second As IObservable(Of T), 
                                comparer As IEqualityComparer(Of T)
                               ) As IObservable(Of T)
    If first Is Nothing Then Throw New ArgumentNullException("first")
    If second Is Nothing Then Throw New ArgumentNullException("second")
    If comparer Is Nothing Then Throw New ArgumentException("comparer")

    Return Observable.Create(Of T)(
        Function(obs)
            Dim gate As New Object()
            Dim firstItems As New HashSet(Of T)(comparer)
            Dim secondItems As New HashSet(Of T)(comparer)
            Dim firstCompleted, secondCompleted As Boolean

            Dim disp As New CompositeDisposable(2)
            disp.Add(first.Subscribe(Sub(v)
                                         SyncLock gate
                                             firstItems.Add(v)
                                             If secondItems.Contains(v) Then obs.OnNext(v)
                                         End SyncLock
                                     End Sub,
                                     AddressOf obs.OnError,
                                     Sub()
                                         SyncLock gate
                                             firstCompleted = True
                                             If secondCompleted Then obs.OnCompleted()
                                         End SyncLock
                                     End Sub))
            disp.Add(second.Subscribe(Sub(v)
                                          SyncLock gate
                                              secondItems.Add(v)
                                              If firstItems.Contains(v) Then obs.OnNext(v)
                                          End SyncLock
                                      End Sub,
                                      AddressOf obs.OnError,
                                      Sub()
                                          SyncLock gate
                                              secondCompleted = True
                                              If firstCompleted Then obs.OnCompleted()
                                          End SyncLock
                                      End Sub))
            Return disp
        End Function)
End Function

如果输入包含多个出现次数,则此实现将重复匹配,但仅在两个源中找到它之后才重复匹配。例如

first  ----1---2---1----2---1---1----|
second ----------2----1-----------|
out    ----------2----1-2---1---1----|

如果不希望重复,您可以检查它是否在相应的源集合中。首先订阅将更改为:

first.Subscribe(Sub(v)
                    SyncLock gate
                        'check that the first doesn't already contain this value
                        If firstItems.Add(v) AndAlso
                           secondItems.Contains(v) Then obs.OnNext(v)
                    End SyncLock
                End Sub,
                AddressOf obs.OnError,
                Sub()
                    SyncLock gate
                        firstCompleted = True
                        If secondCompleted Then obs.OnCompleted()
                    End SyncLock
                End Sub)

第二个订阅的变化相似。

答案 2 :(得分:1)

你不能这样做:

var intersect = from x in stream1
                from y in stream2
                where x == y
                select x;