我爲反應式擴展創建了SlidingWindow()運算符,因爲我想輕鬆地監視諸如滾動平均值等事情。作爲一個簡單示例,我想訂閱聽到鼠標事件,但每次有一個事件我想要接收最後三個(而不是等待每三個事件接收最後三個事件)。這就是爲什麼我發現的Window重載似乎並沒有給我開箱即用的需求。無法在Rx中實現滑動窗口
這就是我想出來的。我擔心它可能不是最高效的解決方案,因爲它頻繁列表操作:
public static IObservable<List<T>> SlidingWindow<T>(this IObservable<T> seq, int length)
{
var seed = new List<T>();
Func<List<T>, T, List<T>> accumulator = (list, arg2) =>
{
list.Add(arg2);
if (list.Count > length)
list.RemoveRange(0, (list.Count - length));
return list;
};
return seq.Scan(seed, accumulator)
.Where(list => list.Count == length);
}
可以這樣調用:
var rollingSequence = Observable.Range(1, 5).SlidingWindow().ToEnumerable();
但是,我很驚訝,而不是接收的預期結果
1,2,3
2,3,4
3,4,5
我收到了效果
2,3,4
3,4,5
3,4,5
任何見解將不勝感激!
@blaster沒問題 - 事實上,感謝「讓」我寫出來,因爲自從回答這個問題以來,我自己使用過幾次。 ;) – JerKimball 2013-03-14 22:07:51
我不認爲這是好事。 .Publish(),.Range(0,x)和.Skip() - 當它們結合在一起時,看起來性能很差,特別是O n^2,因爲Skip會一遍又一遍地迭代整個流。例如,您需要迭代30,000個整數才能獲得(10000,10001,10002)。所以你實際上並沒有在內存中保留源流的滑動緩衝區,你必須將整個源流(從時間的開始)保存在內存中,這是我認爲我們正在避免的。 – yzorg 2013-05-17 06:22:43
@yzorg檢查編輯 – JerKimball 2013-05-17 14:37:43