2011-01-16 2 views
31

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

MyObject 
{ 
    TimeSpan TheDuration { get; set; } 
} 

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

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

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

ответ

74

К сожалению, не существует перегрузки Sum, которая принимает IEnumerable<TimeSpan>. Кроме того, нет текущего способа указания основанных на оператора общих ограничений для параметров типа, поэтому даже если TimeSpan является «изначально» суммируемым, этот факт не может быть легко подхвачен общим кодом.

Один из вариантов заключается в том, чтобы, как вы говорите, суммировать интегральный тип, эквивалентный временному интервалу, а затем повернуть , чтобы сумма снова была пересчитана в TimeSpan. Идеальным свойством для этого является TimeSpan.Ticks, который совершает поездки туда и обратно. Но нет необходимости изменять тип свойства в вашем классе вообще; Вы можете просто проект:

var totalSpan = new TimeSpan(myCollection.Sum(r => r.TheDuration.Ticks)); 

В качестве альтернативы, если вы хотите придерживаться + оператора отрезок времени, чтобы сделать суммирующий, вы можете использовать Aggregate оператор:

var totalSpan = myCollection.Aggregate 
       (TimeSpan.Zero, 
       (sumSoFar, nextMyObject) => sumSoFar + nextMyObject.TheDuration); 
+1

Просто небольшая коррекция. Это должно быть 'var totalSpan = new TimeSpan (myCollection.Sum (r => r.Ticks)); в случае, если 'myCollection is' List () '. –

0

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

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

@Ani: Да, так ...? – CesarGon

0

Вот что я пытался, и она работала:

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

это то же самое, что и первое решение @ Ani, только с выражением запроса вместо точечной нотации – BrokenGlass

+0

@Broken Glass несколько .. к тому времени, когда я отправил этот ответ, было уже 2 ответа на него ..;) Ребята здесь очень быстрые –

1

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

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!

+1

вы должны * запросить * для метода расширения ;;) – BrokenGlass

+1

«Я хочу использовать linq для суммирования этих времен». - Вы изменили свое мнение? –

+0

Я все еще использую linq: я могу запросить мои данные, а затем добавить .TotalTime(); в конце запроса, и он работает. Я все еще изучаю структуру, как вы можете видеть. – frenchie

28

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

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

+1 для чистого ответа. –

0

Я считаю, что это чистое расширение 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

Это работает как для коллекции, а также имущества в коллекции;

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)); 
    } 
}