2008-10-27 71 views
3

我正在設計一個簡單的內部框架來處理時間序列數據。由於LINQ是我目前使用的玩具錘子,我想用它打出一切。「加入」時間序列

我想要實現()選擇(),何地(等)類的TimeSeries方法,使我可以使用LINQ語法來處理時間序列數據

有些東西是直線前進,如(從A選擇x + 10中的x),給出一個新的時間序列。

組合兩個或多個時間序列的最佳語法設計是什麼? (來自A中,B中B選擇a + b)不是很好,因爲它表示一個嵌套循環。 也許一些加入?這應該對應於加入隱式時間變量。 (我心目中對應於LISP '拉鍊' 功能)


編輯:一些澄清是必要的。

時間序列是一種取決於時間的函數,例如,股票報價。 時間序列的組合可能是兩個股票價格之間的差異,作爲時間的函數。

Stock1.MyJoin(Stock2, (a,b)=>a-b) 

是可能的,但是這可以用一些LINQ語法整齊地表達嗎? 我期待在我自己的class MyTimeSeries中實現LINQ方法。

回答

0

如果我正確地理解了這個問題,您想要根據它們在序列中的位置加入多個序列嗎?

由於JoinGroupJoin方法都基於連接鍵,因此System.Linq.Enumerable類中沒有任何內容可以執行此操作。然而,恰巧我寫了PositionalJoin方法只是爲此幾天就回來,作爲你的例子:

sequenceA.PositionalJoin(sequenceB, (a, b) => new { a, b }); 

下圖所示的方法的語義是,它不需要序列是平等的長度,但將其修改爲需要此操作並不重要。我還評論了參數檢查應該如何使用我們的內部幫助類。

public static IEnumerable<TResult> PositionalJoin<T1, T2, TResult>(
    this IEnumerable<T1> source1, 
    IEnumerable<T2> source2, 
    Func<T1, T2, int, TResult> selector) 
{ 
    // argument checking here 
    return PositionalJoinIterator(source1, source2, selector); 
} 

private static IEnumerable<TResult> PositionalJoinIterator<T1, T2, TResult>(
    IEnumerable<T1> source1, 
    IEnumerable<T2> source2, 
    Func<T1, T2, TResult> selector) 
{ 
    using (var enumerator1 = source1.GetEnumerator()) 
    using (var enumerator2 = source2.GetEnumerator()) 
    { 
     bool gotItem; 
     do 
     { 
      gotItem = false; 

      T1 item1; 
      if (enumerator1.MoveNext()) 
      { 
       item1 = enumerator1.Current; 
       gotItem = true; 
      } 
      else 
      { 
       item1 = default(T1); 
      } 

      T2 item2; 
      if (enumerator2.MoveNext()) 
      { 
       item2 = enumerator2.Current; 
       gotItem = true; 
      } 
      else 
      { 
       item2 = default(T2); 
      } 

      if (gotItem) 
      { 
       yield return selector(item1, item2); 
      } 
     } 
     while (gotItem); 
    } 
} 

不知道這是否正是你想要的,但希望有一些幫助。

+0

我的細節比較複雜,因爲兩個時間序列可能沒有完全相同的時間戳,但這個想法與您所描述的相同。 我懷疑LINQ查詢語法不夠。 感謝您詳細說明爲何如此。 – 2008-10-27 23:50:48

1

Union聽起來像是正確的方式 - 沒有查詢表達式的支持,但我認爲它表達了你的意思。

您可能有興趣查看MiscUtil中的基於範圍的類,它可以很好地用於時間。有位的擴展方法相結合的樂趣,你可以這樣做:

foreach (DateTime day in 19.June(1976).To(DateTime.Today).Step(1.Day())) 
{ 
    Console.WriteLine("I'm alive!"); 
} 

我並不是說這應該替換無論你做什麼,只是你也許可以採取一些想法,使其更整潔。請隨時回饋:)

+0

我真的不喜歡這個例子,因爲它擴展了一個基本類型(int),這只是不好的做法。 – 2008-10-27 21:46:58

+0

「構建日期時間」部分有一點似是而非,但能夠通過執行1.To(10)來構建範圍,這使得代碼非常易讀。 – 2008-10-27 21:55:33

1

從我NExtension項目:

public static IEnumerable<TResult> Zip<T1, T2, TResult>(
    this IEnumerable<T1> source1, 
    IEnumerable<T2> source2, 
    Func<T1, T2, TResult> combine) 
{ 
    if (source1 == null) 
     throw new ArgumentNullException("source1"); 
    if (source2 == null) 
     throw new ArgumentNullException("source2"); 
    if (combine == null) 
     throw new ArgumentNullException("combine"); 

    IEnumerator<T1> data1 = source1.GetEnumerator(); 
    IEnumerator<T2> data2 = source2.GetEnumerator(); 
    while (data1.MoveNext() && data2.MoveNext()) 
    { 
     yield return combine(data1.Current, data2.Current); 
    } 
} 

語法是:

Stock1.Zip(Stock2, (a,b)=>a-b) 
+1

請注意,您應該將參數檢查和迭代分隔爲不同的方法 - 有關詳細信息,請參閱http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx。 – 2008-10-27 22:30:05

1

Bjarke,看看NEsper,它是一個開源的複雜事件處理應用程序,除其他事情做類似SQL的時間序列查詢。你可以學習他們如何完成它,或者甚至可以利用他們的代碼來實現你的目標。這裏鏈接http://esper.codehaus.org/about/nesper/nesper.html