2011-02-12 97 views
2

我正在學習LINQ,並希望獲得與下面代碼等效的LINQ查詢。C#LINQ TimeSpan平均天數

IEnumerable列表包含一個排序的日期列表:從最舊到最新。

以下代碼通過從數組的第一個元素日期減去數組的第零個元素日期,從第二個元素日期減去第二個元素日期,從第三個元素減去第二個元素日期等等,得出TimeSpan s。然後在代碼中的其他地方對TimeSpan.Days進行平均。我相信LINQ查詢不需要構建數組。 IEnumerable<DateTime>結構可以用作數據源。

IEnumerable<DateTime> list; // contains a sorted list of oldest to newest dates 

// build DateTime array 

DateTime[] datesArray = null; 
TimeSpan ts; 
List<int> daysList = new List<int>(); 

datesArray = (from dt in list 
       select dt).ToArray(); 

// loop through the array and derive the TimeSpan by subtracting the previous date, 
// contained in the previous array element, from the date in the current array element. 
// start the loop at element 1. 

for (int i = 1; i < list.Count(); i++) 
{ 
    ts = datesArray[i].Subtract(datesArray[i - 1]); // ts is a TimeSpan type 
    daysList.Add(ts.Days); 
    // add the TimeSpan.Days to a List<int> for averaging elsewhere. 
} 

謝謝

斯科特

+0

`(DT從列表中選擇DT).ToArray()`是更好的寫作`list.ToArray()`` – Gabe 2011-02-12 01:47:58

回答

4

我想你想:

double averageDays = list 
        .Skip(1) 
        .Zip(list, (next, prev) => (double)next.Subtract(prev).Days) 
        .Average(); 

請注意,這是一個有損平均水平。你確定你不想使用TotalDays嗎?

編輯:

這個作品是與序列,這使得它容易計算出連續增量的一個「遞延」版本覆蓋序列的方式。然後,只需要平均三角形就可以產生結果。

爲了比較,現有的代碼的「忠實」翻譯會是什麼樣子:

double averageDays = Enumerable 
        .Range(1, list.Count - 1) 
        .Average(i => (double)list[i].Subtract(list[i - 1]).Days); 
+1

Zip`似乎有點不必要在這裏,應該是可行的用`Aggregate`。 – 2011-02-12 01:15:15

+1

...但理解代碼的意圖相當容易。雖然`Aggregate`方便,它使醜陋的代碼不明顯。 – spender 2011-02-12 02:24:16

+0

Linq Zip是一個框架4.0。我需要一個Framework 3.5或更低版本的解決方案。我還需要一個統計分析的單個日期增量列表,超過平均值。 – scottL 2011-02-13 23:13:21

1

這被安排成更Lispy縮進風格強調功能性的風格,避免流失到上滾動條土地頁面的右側。

list.Skip(1) 
    .Aggregate(new { Previous = list.FirstOrDefault(), 
        Sum = 0.0, 
        Count = 0 }, 
       (a, n) => new { Previous = n, 
           Sum = a.Sum + (n - a.Previous).Days, 
           Count = a.Count + 1 }, 
       a => a.Sum/a.Count) 
2

如果您只需要一個平均值,那麼您不需要檢查列表中的所有元素。你只需要第一個和最後一個。

var period = list.Last() - list.First(); 
var averageDays = (double)period.TotalDays/(list.Count() - 1);