Сумма временных интервалов в C # - PullRequest
40 голосов
/ 16 января 2011

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

MyObject
{ 
    TimeSpan TheDuration { get; set; }
}

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

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

Есть предложения по суммированию?

Ответы [ 7 ]

95 голосов
/ 16 января 2011

К сожалению, нет перегрузки 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);
34 голосов
/ 01 ноября 2012

Это хорошо работает (код основан на ответе Ани)

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)
1 голос
/ 18 января 2011

Я поместил это в класс, чтобы добавить метод расширения к коллекции временных интервалов:

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, который возвращает коллекцию временного интервала) .TotalTime ();

Voila!

0 голосов
/ 15 июня 2017

Это работает как для коллекции, так и для свойства в коллекции;

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));
    }
}
0 голосов
/ 08 марта 2017

Я считаю, что это самое чистое расширение 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)
0 голосов
/ 16 января 2011

Вот что я попробовал, и это сработало:

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; }
}
0 голосов
/ 16 января 2011

Вы можете использовать .Aggregate вместо .Sum и передать ему функцию суммирования временного интервала, которую вы пишете, например:

    TimeSpan AddTimeSpans(TimeSpan a, TimeSpan b)
    {
        return a + b;
    }
...