我有一组包含TimeSpan变量的对象:
MyObject
{
TimeSpan TheDuration { get; set; }
}
我想用LINQ来总结这些时间。 当然,(来自MyCollection中的r选择r.TheDuration).Sum();不起作用!
我正在考虑将TheDuration的数据类型更改为int,然后将其求和并将总和转换为TimeSpan。这将是混乱的,因为我的集合中的每个TheDuration都用作其他地方的时间跨度。
有关此总结的任何建议吗?
答案 0 :(得分:93)
不幸的是,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);
答案 1 :(得分:34)
这很好用(基于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)
答案 2 :(得分:1)
我把它放在一个类中,为时间盘的集合添加扩展方法:
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();
瞧!
答案 3 :(得分:0)
您可以使用.Aggregate
而不是.Sum
,并将其传递给您编写的时间总和函数,如下所示:
TimeSpan AddTimeSpans(TimeSpan a, TimeSpan b)
{
return a + b;
}
答案 4 :(得分: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; }
}
答案 5 :(得分: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)
答案 6 :(得分: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));
}
}
答案 7 :(得分:0)
一旦您了解到不能将时间跨度相加并且知道使用Ticks
,那么在我看来,对 just 的这种扩展将很长的时间跨度转换为时间跨度[em] 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);
}