[英]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.