如何计算C#中某些时间跨度的平均值
How to calculate average of some timespans in C#
我已经搜索过这个问题,但不幸的是找不到合适的答案。
我想计算 10 天做某事的平均时间,我有 10 datetimepicker
作为开始时间,还有 10 datetimepicker
作为每天的结束时间(总计20 datetimepicker
).
现在我想得到这10天的平均工作时间。
这就是我每天计算 timespan
的方法,现在我不知道如何计算这些 timespans
的平均值
当然我想知道有没有更短的方法来完成这项工作?
DateTime Dt1 = dateTimePicker1.Value;
DateTime Dt2 = dateTimePicker2.Value;
.
.
.
DateTime Dt20 = dateTimePicker20.Value;
TimeSpan Day1 = DateTime.Parse(Dt11.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt1.TimeOfDay.ToString()));
TimeSpan Day2 = DateTime.Parse(Dt12.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt2.TimeOfDay.ToString()));
.
.
.
TimeSpan Day10 = DateTime.Parse(Dt20.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt10.TimeOfDay.ToString()));
我想求第 1 天到第 10 天的平均值
给定一个 IEnumerable<TimeSpan>
你可以用这个扩展方法对它们进行平均:
public static TimeSpan Average(this IEnumerable<TimeSpan> spans) => TimeSpan.FromSeconds(spans.Select(s => s.TotalSeconds).Average());
因此,将您的结果转换为 List
:
var durs = new List<TimeSpan>();
durs.Add(Dt11.TimeOfDay.Subtract(Dt1.TimeOfDay));
durs.Add(Dt12.TimeOfDay.Subtract(Dt2.TimeOfDay));
.
.
.
durs.Add(Dt20.TimeOfDay.Subtract(Dt10.TimeOfDay));
现在计算平均值:
var avgDurs = durs.Average();
PS:创建了一个 Aggregate
版本的@MattJohnson 的回答:
public static TimeSpan Mean(this IEnumerable<TimeSpan> source) => TimeSpan.FromTicks(source.Aggregate((m: 0L, r: 0L, n: source.Count()), (tm, s) => {
var r = tm.r + s.Ticks % tm.n;
return (tm.m + s.Ticks / tm.n + r / tm.n, r % tm.n, tm.n);
}).m);
您可以根据滴答数实例化一个新的 TimeSpan 来求平均值。
var time_spans = new List<TimeSpan>() { new TimeSpan(24, 10, 0), new TimeSpan(12, 0, 45), new TimeSpan(23, 30, 0), new TimeSpan(11, 34, 0) };
var average = new TimeSpan(Convert.ToInt64(time_spans.Average(t => t.Ticks)));
Console.WriteLine(average);
结果17:48:41.2500000
只是为了跟进 NetMage 的完美答案,请注意他的 Average
扩展方法正在使用 .TotalSeconds
,其中 returns double
整秒和小数秒, 以毫秒为单位。如果您从时间选择器中获取值,这可能没问题,但在 general 情况下,它会导致精度损失很小。
此外,TimeSpan.FromSeconds
方法在处理大值时可能会溢出。即使不平均也可以重现:
TimeSpan.FromSeconds(TimeSpan.MaxValue.TotalSeconds) // will throw an OverflowException
Patrick Hofman 在评论中提出了一个很好的观点,即从秒切换到滴答也可能导致溢出,因此需要另一种解决方案。
采用 this answer, we can compute the average of a collection of TimeSpan
values using an arithmetic mean 方法中给出的技术,不损失精度且不溢出:
public static TimeSpan Mean(this ICollection<TimeSpan> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
long mean = 0L;
long remainder = 0L;
int n = source.Count;
foreach (var item in source)
{
long ticks = item.Ticks;
mean += ticks / n;
remainder += ticks % n;
mean += remainder / n;
remainder %= n;
}
return TimeSpan.FromTicks(mean);
}
与其他扩展方法类似地使用它,例如:
TimeSpan average = mylistoftimespans.Mean();
我已经搜索过这个问题,但不幸的是找不到合适的答案。
我想计算 10 天做某事的平均时间,我有 10 datetimepicker
作为开始时间,还有 10 datetimepicker
作为每天的结束时间(总计20 datetimepicker
).
现在我想得到这10天的平均工作时间。
这就是我每天计算 timespan
的方法,现在我不知道如何计算这些 timespans
当然我想知道有没有更短的方法来完成这项工作?
DateTime Dt1 = dateTimePicker1.Value;
DateTime Dt2 = dateTimePicker2.Value;
.
.
.
DateTime Dt20 = dateTimePicker20.Value;
TimeSpan Day1 = DateTime.Parse(Dt11.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt1.TimeOfDay.ToString()));
TimeSpan Day2 = DateTime.Parse(Dt12.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt2.TimeOfDay.ToString()));
.
.
.
TimeSpan Day10 = DateTime.Parse(Dt20.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt10.TimeOfDay.ToString()));
我想求第 1 天到第 10 天的平均值
给定一个 IEnumerable<TimeSpan>
你可以用这个扩展方法对它们进行平均:
public static TimeSpan Average(this IEnumerable<TimeSpan> spans) => TimeSpan.FromSeconds(spans.Select(s => s.TotalSeconds).Average());
因此,将您的结果转换为 List
:
var durs = new List<TimeSpan>();
durs.Add(Dt11.TimeOfDay.Subtract(Dt1.TimeOfDay));
durs.Add(Dt12.TimeOfDay.Subtract(Dt2.TimeOfDay));
.
.
.
durs.Add(Dt20.TimeOfDay.Subtract(Dt10.TimeOfDay));
现在计算平均值:
var avgDurs = durs.Average();
PS:创建了一个 Aggregate
版本的@MattJohnson 的回答:
public static TimeSpan Mean(this IEnumerable<TimeSpan> source) => TimeSpan.FromTicks(source.Aggregate((m: 0L, r: 0L, n: source.Count()), (tm, s) => {
var r = tm.r + s.Ticks % tm.n;
return (tm.m + s.Ticks / tm.n + r / tm.n, r % tm.n, tm.n);
}).m);
您可以根据滴答数实例化一个新的 TimeSpan 来求平均值。
var time_spans = new List<TimeSpan>() { new TimeSpan(24, 10, 0), new TimeSpan(12, 0, 45), new TimeSpan(23, 30, 0), new TimeSpan(11, 34, 0) };
var average = new TimeSpan(Convert.ToInt64(time_spans.Average(t => t.Ticks)));
Console.WriteLine(average);
结果17:48:41.2500000
只是为了跟进 NetMage 的完美答案,请注意他的 Average
扩展方法正在使用 .TotalSeconds
,其中 returns double
整秒和小数秒, 以毫秒为单位。如果您从时间选择器中获取值,这可能没问题,但在 general 情况下,它会导致精度损失很小。
此外,TimeSpan.FromSeconds
方法在处理大值时可能会溢出。即使不平均也可以重现:
TimeSpan.FromSeconds(TimeSpan.MaxValue.TotalSeconds) // will throw an OverflowException
Patrick Hofman 在评论中提出了一个很好的观点,即从秒切换到滴答也可能导致溢出,因此需要另一种解决方案。
采用 this answer, we can compute the average of a collection of TimeSpan
values using an arithmetic mean 方法中给出的技术,不损失精度且不溢出:
public static TimeSpan Mean(this ICollection<TimeSpan> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
long mean = 0L;
long remainder = 0L;
int n = source.Count;
foreach (var item in source)
{
long ticks = item.Ticks;
mean += ticks / n;
remainder += ticks % n;
mean += remainder / n;
remainder %= n;
}
return TimeSpan.FromTicks(mean);
}
与其他扩展方法类似地使用它,例如:
TimeSpan average = mylistoftimespans.Mean();