繁体   English   中英

C# 中时间跨度的总和

[英]Sum of TimeSpans in C#

我有一个包含 TimeSpan 变量的对象集合:

MyObject
{ 
    TimeSpan TheDuration { get; set; }
}

我想用 LINQ 来总结那些时间。 当然,(来自 MyCollection 中的 r select r.TheDuration).Sum(); 不起作用!

我正在考虑将 TheDuration 的数据类型更改为 int,然后对其求和并将总和转换为 TimeSpan。 这会很麻烦,因为我收藏中的每个 TheDuration 都在其他地方用作时间跨度。

对这个总结有什么建议吗?

不幸的是,没有接受IEnumerable<TimeSpan>Sum重载。 此外,目前还没有为类型参数指定基于运算符的泛型约束的方法,因此即使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);

这很有效(基于 Ani 的答案的代码)

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)

我相信这是最干净的 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)

这是我尝试过的并且有效:

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

我把它放在一个类中以向时间跨度集合添加扩展方法:

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

瞧!

我为 IEnumerable<TimeSpan> 创建了扩展方法

public static class TimeSpanExtensions
{
    public static TimeSpan Sum(this IEnumerable<TimeSpan> source)
    {
        return source.Aggregate(TimeSpan.Zero, (subtotal, time) => subtotal.Add(time));
    }
}

多亏了我可以使用:

 IEnumerable<TimeSpan> times = new List<TimeSpan>();
 TimeSpan totalTime = times.Sum();

这适用于集合和集合中的属性;

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

您可以使用.Aggregate而不是.Sum ,并将您编写的时间跨度求和函数传递给它,如下所示:

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

一旦你理解了时间跨度不能相加并知道使用Ticks ,在我看来,这个只是将 long 转换为时间跨度的扩展看起来更linq-ee 我相信它可以让读者对操作有一个更易读的视图:

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
     

这是一个扩展:

public static class LongExtensions
{
    public static TimeSpan ToTimeSpan(this long ticks)
        => new TimeSpan(ticks);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM