2011-02-12 51 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);