如何在C#中使用LINQ计算时间戳序列的差值极值与平均值
使用LINQ简化DateTimeOffset序列相邻时间差统计逻辑
我有一个无序的DateTimeOffset时间戳序列,需要计算相邻时间戳差值的最小值(Min)、最大值(Max)以及平均值(Average)。
示例数据
DateTimeOffset now = new DateTimeOffset(new DateTime(2022, 1, 1, 0, 0, 0, 0)); DateTimeOffset[] timestamps = new[] { now, now.AddSeconds(5), now.AddSeconds(10), now.AddSeconds(15), now.AddSeconds(30), now.AddSeconds(31) }; IEnumerable<DateTimeOffset> timestampsSorted = timestamps.OrderByDescending(x => x);
预期输出
2022-01-01 00:00:31->2022-01-01 00:00:30 | 00:00:01 2022-01-01 00:00:30->2022-01-01 00:00:15 | 00:00:15 2022-01-01 00:00:15->2022-01-01 00:00:10 | 00:00:05 2022-01-01 00:00:10->2022-01-01 00:00:05 | 00:00:05 2022-01-01 00:00:05->2022-01-01 00:00:00 | 00:00:05 Min 00:00:01 Max 00:00:15 Avg 00:00:06.2000000
现有过程式实现
TimeSpan min = TimeSpan.MaxValue; TimeSpan max = TimeSpan.MinValue; List<TimeSpan> deltas = new(); for (int i = timestampsSorted.Count() - 1; i > 0; i--) { DateTimeOffset later = timestamps.ElementAt(i); DateTimeOffset prev = timestamps.ElementAt(i - 1); TimeSpan delta = later - prev; if (delta > max) { max = delta; } if (delta < min) { min = delta; } deltas.Add(delta); Console.WriteLine($"{later:yyyy-MM-dd HH:mm:ss}->{prev:yyyy-MM-dd HH:mm:ss} | {delta}"); } var result = new { Min = min, Max = max, Avg = TimeSpan.FromMilliseconds(deltas.Average(d => d.TotalMilliseconds)) };
LINQ简化方案
利用LINQ的Zip方法可以快速生成相邻时间戳对,同时完成差值计算和统计,代码更简洁:
// 先对时间戳降序排序并转为列表,避免多次枚举 var sortedTimestamps = timestamps.OrderByDescending(t => t).ToList(); // 生成包含相邻时间戳及差值的集合 var deltaDetails = sortedTimestamps .Zip(sortedTimestamps.Skip(1), (later, prev) => new { LaterTime = later, PreviousTime = prev, TimeDelta = later - prev }) .ToList(); // 转为列表,避免后续多次遍历原序列 // 输出每一组时间差详情 foreach (var detail in deltaDetails) { Console.WriteLine($"{detail.LaterTime:yyyy-MM-dd HH:mm:ss}->{detail.PreviousTime:yyyy-MM-dd HH:mm:ss} | {detail.TimeDelta}"); } // 计算统计结果 var result = new { MinDelta = deltaDetails.Min(d => d.TimeDelta), MaxDelta = deltaDetails.Max(d => d.TimeDelta), AvgDelta = TimeSpan.FromMilliseconds(deltaDetails.Average(d => d.TimeDelta.TotalMilliseconds)) }; // 输出统计信息 Console.WriteLine($"\nMin {result.MinDelta}"); Console.WriteLine($"Max {result.MaxDelta}"); Console.WriteLine($"Avg {result.AvgDelta}");
简化说明
Zip配对相邻元素:通过Zip将排序后的序列与跳过第一个元素的序列配对,直接得到每一组前后时间戳,同时计算出差值。- 一次性生成数据:将结果转为列表,避免后续操作多次枚举原序列,提升效率。
- LINQ内置方法统计:直接使用
Min、Max、Average方法完成统计,无需手动遍历比较。
内容的提问来源于stack exchange,提问作者MaYaN
相关产品推荐
相关产品推荐

