C # LINQ TimeSpan Среднее число дней - PullRequest
2 голосов
/ 12 февраля 2011

Я изучаю LINQ и хочу запрос LINQ, эквивалентный следующему коду.

Список IEnumerable содержит отсортированный список дат: от самой старой к самой новой.

Приведенный ниже код выводит TimeSpan s, вычитая дату нулевого элемента массива из даты первого элемента массива, первого элементадата от 2-го, 2-го от 3-го и так далее.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 ]

4 голосов
/ 12 февраля 2011

Я думаю, что вы хотите:

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);
2 голосов
/ 12 февраля 2011

Если вам нужно только среднее значение, вам не нужно проверять все элементы в списке.Вам нужен только первый и последний.

var period = list.Last() - list.First();
var averageDays = (double)period.TotalDays / (list.Count() - 1);
1 голос
/ 12 февраля 2011

Это оформлено в более гибкий стиль 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)
...