2016-02-26 107 views
1

我在寻找Observable.Window like opener with opening window选择器将窗口拆分为窗口

例如,我们可以采用一系列自然数。 我想知道如何将该序列分割成窗口,以便每一个新的窗口开始,如果数目大于4或窗口大小已经达到3

输入序列IObservable<int> 输出序列是IObservable<IObservable<int>>

序列1 2 5 3 1 1 2 3 1 5 0 将产生窗户1 2; 5 3 1; 1 2 3; 1; 5 0

+0

应该'1,2,3,5'生产窗户'1 2 3; 5'或'1 2 3; ; 5'? (注意空的窗口) – Lukazoid

+0

对不起,';' - 是所需序列之间的分隔符 – bublegumm

+0

我明白,但是在输入序列1,2,3,5上运行这两个答案并且它们会产生不同的结果。 – Lukazoid

回答

2

使用C#这样工作的:

var observable = 
    source 
     .Concat(Observable.Return(-1)) 
     .Publish(sp => 
      sp.Zip(sp.Skip(1), (x0, x1) => new { x0, x1 }) 
       .Publish(zsp => 
        zsp 
         .Window(zsp.Where(x => x.x1 >= 4)) 
         .Select(xs => xs.Select(x => x.x0).Window(3)) 
         .Merge())); 

我得到这样的结果:

result

+0

您用于可视化“可观察”结果的工具是什么? – supertopi

+0

@supertopi - 它是[LINQPad](https://www.linqpad.net/)。 – Enigmativity

1

按我对我不确定序列1, 2, 3, 5是否应该产生的窗口的问题评论1 2 3 | 51 2 3 | | 5(请参阅Enigmativity答案产生的空窗口)。我的回答不会产生空窗:

public static IObservable<IObservable<T>> Window<T>(this IObservable<T> source, Func<T, bool> predicate, int maximumWindowSize) 
{ 
    return Observable.Create<IObservable<T>>(obs => 
    { 
     var currentWindow = new Subject<T>(); 
     obs.OnNext(currentWindow); 

     var count = 0; 

     return source.Subscribe(x => 
     { 
      if (count == maximumWindowSize || predicate(x)) 
      { 
       count = 0; 
       currentWindow.OnCompleted(); 
       currentWindow = new Subject<T>(); 
       obs.OnNext(currentWindow); 
      } 
      currentWindow.OnNext(x); 
      count++; 
     }, obs.OnError,() => 
     { 
      obs.OnCompleted(); 
      currentWindow.OnCompleted(); 
     }); 
    }); 
} 

这可以用于像这样:

var windows = source.Window(x => x > 4, 3); 
+0

我测试了我的并没有在中间得到空的结果。你可以发布你用来测试我的代码的代码吗? – Enigmativity

+0

http://share.linqpad.net/klomqj.linq是我跑的代码。 – Lukazoid