Sum of TimeSpans in C#

前端 未结 8 960
执笔经年
执笔经年 2020-11-29 06:01

I have a collection of objects that include a TimeSpan variable:

MyObject
{ 
    TimeSpan TheDuration { get; set; }
}

I want to use LINQ to

相关标签:
8条回答
  • 2020-11-29 06:41

    I put this in a class to add an extension method to a collection of 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);
        }
    }
    

    So now, I can write TotalDuration = (my LINQ query that returns a collection of timespan).TotalTime();

    Voila!

    0 讨论(0)
  • 2020-11-29 06:41

    Once you understand that timespans can't be summed and know to use Ticks, it seems to me that this extension to just convert a long into a timespan looks more linq-ee. I believe it lets the reader have a more readable view of the operation:

    var times = new[] { new TimeSpan(0, 10, 0), new TimeSpan(0, 20, 0), new TimeSpan(0, 30, 0) };
    
    times.Sum(p => p.Ticks)
         .ToTimeSpan();      // output: 01:00:00
         
    

    Here is the one extension:

    public static class LongExtensions
    {
        public static TimeSpan ToTimeSpan(this long ticks)
            => new TimeSpan(ticks);
    }
    
    0 讨论(0)
  • 2020-11-29 06:48

    I believe this is the cleanest LINQ extension:

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

    Usage is the same:

    TimeSpan total = Periods.Sum(s => s.Duration)
    
    0 讨论(0)
  • 2020-11-29 06:48

    Here's what I tried and it worked:

    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 讨论(0)
  • 2020-11-29 06:51

    Unfortunately, there isn't a an overload of Sum that accepts an IEnumerable<TimeSpan>. Additionally, there's no current way of specifying operator-based generic constraints for type-parameters, so even though TimeSpan is "natively" summable, that fact can't be picked up easily by generic code.

    One option would be to, as you say, sum up an integral-type equivalent to the timespan instead, and then turn that sum into a TimeSpan again. The ideal property for this is TimeSpan.Ticks, which round-trips accurately. But it's not necessary to change the property-type on your class at all; you can just project:

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

    Alternatively, if you want to stick to the TimeSpan's + operator to do the summing, you can use the Aggregate operator:

    var totalSpan = myCollection.Aggregate
                    (TimeSpan.Zero, 
                    (sumSoFar, nextMyObject) => sumSoFar + nextMyObject.TheDuration);
    
    0 讨论(0)
  • 2020-11-29 06:57

    This works for both a collection, and a property within a collection;

    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 讨论(0)
提交回复
热议问题