Сумма TimeSpans в С#
У меня есть набор объектов, которые включают переменную TimeSpan:
MyObject
{
TimeSpan TheDuration { get; set; }
}
Я хочу использовать LINQ для суммирования этих времен.
Конечно, (из r в MyCollection выберите r.TheDuration).Sum(); не работает!
Я собираюсь изменить тип данных TheDuration на int, а затем суммировать его и преобразовать сумму в TimeSpan. Это будет беспорядочно, потому что каждый TheDuration в моей коллекции используется как промежуток времени где-то еще.
Любое предложение по этому суммированию?
Ответы
Ответ 1
К сожалению, не существует перегрузки Sum
, которая принимает IEnumerable<TimeSpan>
. Кроме того, нет текущего способа указания основанных на оператора общих ограничений для параметров типа, поэтому даже если TimeSpan
"изначально" суммируется, этот факт не может быть легко скомбинирован с помощью общего кода.
Один из вариантов был бы, как вы говорите, суммировать интегральный тип, эквивалентный периоду времени, а затем снова включить эту сумму в TimeSpan
. Идеальным свойством для этого является TimeSpan.Ticks
, который точно округляется. Но не обязательно менять тип свойства на свой класс вообще; вы можете просто спроектировать:
var totalSpan = new TimeSpan(myCollection.Sum(r => r.TheDuration.Ticks));
В качестве альтернативы, если вы хотите придерживаться оператора TimeSpan +
для выполнения суммирования, вы можете использовать оператор Aggregate
:
var totalSpan = myCollection.Aggregate
(TimeSpan.Zero,
(sumSoFar, nextMyObject) => sumSoFar + nextMyObject.TheDuration);
Ответ 2
Это хорошо работает (код основан на ответе Ани)
public static class StatisticExtensions
{
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> selector)
{
return source.Select(selector).Aggregate(TimeSpan.Zero, (t1, t2) => t1 + t2);
}
}
Использование:
Если Periods - это список объектов с свойством Duration
TimeSpan total = Periods.Sum(s => s.Duration)
Ответ 3
Я помещаю это в класс, чтобы добавить метод расширения в коллекцию временных рядов:
public static class Extensions:
{
public static TimeSpan TotalTime(this IEnumerable<TimeSpan> TheCollection)
{
int i = 0;
int TotalSeconds = 0;
var ArrayDuration = TheCollection.ToArray();
for (i = 0; i < ArrayDuration.Length; i++)
{
TotalSeconds = (int)(ArrayDuration[i].TotalSeconds) + TotalSeconds;
}
return TimeSpan.FromSeconds(TotalSeconds);
}
}
Итак, теперь я могу написать TotalDuration = (мой запрос LINQ, который возвращает коллекцию timespan).TotalTime();
Voila!
Ответ 4
Вы можете использовать .Aggregate
, а не .Sum
, и передать ему функцию суммирования по времени, которую вы пишете, например:
TimeSpan AddTimeSpans(TimeSpan a, TimeSpan b)
{
return a + b;
}
Ответ 5
Вот что я пробовал и работал:
System.Collections.Generic.List<MyObject> collection = new List<MyObject>();
MyObject mb = new MyObject();
mb.TheDuration = new TimeSpan(100000);
collection.Add(mb);
mb.TheDuration = new TimeSpan(100000);
collection.Add(mb);
mb.TheDuration = new TimeSpan(100000);
collection.Add(mb);
var sum = (from r in collection select r.TheDuration.Ticks).Sum();
Console.WriteLine( sum.ToString());
//here we have new timespan that is sum of all time spans
TimeSpan sumedup = new TimeSpan(sum);
public class MyObject
{
public TimeSpan TheDuration { get; set; }
}
Ответ 6
Я считаю, что это самое чистое расширение LINQ:
public static class LinqExtensions
{
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> func)
{
return new TimeSpan(source.Sum(item => func(item).Ticks));
}
}
Использование одинаковое:
TimeSpan total = Periods.Sum(s => s.Duration)
Ответ 7
Это работает как для коллекции, так и для свойства внутри коллекции;
void Main()
{
var periods = new[] {
new TimeSpan(0, 10, 0),
new TimeSpan(0, 10, 0),
new TimeSpan(0, 10, 0),
};
TimeSpan total = periods.Sum();
TimeSpan total2 = periods.Sum(p => p);
Debug.WriteLine(total);
Debug.WriteLine(total2);
// output: 00:30:00
// output: 00:30:00
}
public static class LinqExtensions
{
public static TimeSpan Sum(this IEnumerable<TimeSpan> timeSpanCollection)
{
return timeSpanCollection.Sum(s => s);
}
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> func)
{
return new TimeSpan(source.Sum(item => func(item).Ticks));
}
}