C#LINQ TimeSpan平均天数

时间:2011-02-12 01:09:42

标签: c# linq timespan

我正在学习LINQ,并希望LINQ查询等同于以下代码。

IEnumerable列表包含一个排序的日期列表:最旧到最新。

下面的代码通过从数组的第一个元素日期减去数组的第0个元素日期,从第2个元素减去第2个元素日期,从第3个元素减去第2个元素日期来推导TimeSpan,依此类推。然后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.
 }

谢谢,

斯科特

3 个答案:

答案 0 :(得分: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 :(得分:2)

如果您只需要平均值,则无需检查列表中的所有元素。你只需要第一个和最后一个。

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

答案 2 :(得分: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)