Подтвердить что ты не робот

Сумма TimeSpans в С#

У меня есть набор объектов, которые включают переменную TimeSpan:

MyObject
{ 
    TimeSpan TheDuration { get; set; }
}

Я хочу использовать LINQ для суммирования этих времен. Конечно, (из r в MyCollection выберите r.TheDuration).Sum(); не работает!

Я собираюсь изменить тип данных TheDuration на int, а затем суммировать его и преобразовать сумму в TimeSpan. Это будет беспорядочно, потому что каждый TheDuration в моей коллекции используется как промежуток времени где-то еще.

Любое предложение по этому суммированию?

4b9b3361

Ответ 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));
    }
}