Демонстрация красоты LINQ путем написания метода расширения.
/// <summary>
/// Gets the duration of the set union of the specified intervals.
/// </summary>
/// <param name="timeLapses">Sequence of <see cref="TimeLapse"/> ordered by <see cref="TimeLapse.StartTime"/>.</param>
public static TimeSpan UnionDurations(this IEnumerable<TimeLapse> timeLapses)
{
using (var e = timeLapses.GetEnumerator())
{
if (!e.MoveNext()) // no items, no duration
return TimeSpan.Zero;
var prev = e.Current;
var total = prev.EndTime - prev.StartTime; // set running total to duration of 1st interval
while (e.MoveNext())
{
var curr = e.Current;
if (curr.StartTime < prev.StartTime) throw new Exception($"{nameof(timeLapses)} are not in ascending {nameof(TimeLapse.StartTime)} order.");
var increase = curr.EndTime - (curr.StartTime > prev.EndTime ? curr.StartTime : prev.EndTime);
if (increase <= TimeSpan.Zero) continue;
total += increase;
prev = curr;
}
return total;
}
}
Тестовый код:
var input = new Dictionary<string, IList<TimeLapse>>
{
{
"A",
new[]
{
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 0, 0, 0), EndTime = new DateTime(2019, 1, 17, 3, 0, 0)},
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 1, 0, 0), EndTime = new DateTime(2019, 1, 17, 2, 0, 0)},
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 1, 0, 0), EndTime = new DateTime(2019, 1, 17, 4, 0, 0)},
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 5, 0, 0), EndTime = new DateTime(2019, 1, 17, 7, 0, 0)}
}
},
{
"B",
new TimeLapse [0]
}
};
var result = input
.Select(kv => new
{
Device = kv.Key,
FaultyDuration = kv.Value
// .OrderBy(tl => tl.StartTime) // this line can be removed if already ordered by StartTime
.UnionDurations()
})
.ToList();
// { Device = A, FaultyDuration = 06:00:00 }
// { Device = B, FaultyDuration = 00:00:00 }