我正试图找到一种方法来计算特定设备因具有StartTime和EndTime的各种错误而出现故障的总秒数,这些错误可能在同一时刻发生,但持续时间不同。 / p>
这是我拥有的DateTime的集合:
private class TimeLapse
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
Dictionary<string, List<TimeLapse>> _devices = new Dictionary<string, List<TimeLapse>>();
其中字典中的字符串是设备的名称;
但是我不知道从哪里开始不编写令人作呕的代码来做到这一点。 任何人都有相同的问题要解决吗?
答案 0 :(得分:4)
执行此操作的一种方法是使用其他方法扩展您的类,该方法将合并TimeLapse
个对象列表,方法是将重叠的对象合并成一个TimeLapse
,然后返回这套。如果执行此操作,则只需将集合中每个项目的持续时间加起来即可。您还可以添加一个属性,该属性公开Duration
对象的TimeLapse
:
private class TimeLapse
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration => (EndTime - StartTime).Duration();
public static List<TimeLapse> Merge(List<TimeLapse> items)
{
if (items == null || items.Count < 2) return items;
var results = new List<TimeLapse>();
foreach (var item in items)
{
var overlappingItem = results.FirstOrDefault(item.OverlapsWith);
if (overlappingItem == null) results.Add(item);
else overlappingItem.CombineWith(item);
}
return results;
}
private bool OverlapsWith(TimeLapse other)
{
return other != null &&
other.StartTime <= EndTime &&
other.EndTime >= StartTime;
}
private void CombineWith(TimeLapse other)
{
if (!OverlapsWith(other)) return;
if (other.StartTime < StartTime) StartTime = other.StartTime;
if (other.EndTime > EndTime) EndTime = other.EndTime;
}
}
以下是如何显示词典中每个项目的持续时间的示例。
我提供了一种生成设备虚拟列表的方法,所以我使用Days
是因为它更容易编写和验证结果是否正确,但是由于Duration
是{ {1}},您几乎可以获得所需的任何度量单位(例如TimeSpan
):
TotalSeconds
输出
答案 1 :(得分:1)
通过编写扩展方法来演示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 }
答案 2 :(得分:0)
我不确定您会认为“令人作呕的”是什么,但是如果您只希望每次间隔时间都用几秒钟,则可以为TimeLapse类创建一个返回该方法的方法。
private class TimeLapse
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public double GetSecondsPassed() {
return (EndTime - StartTime).TotalSeconds
}
}
两个DateTime对象之间的差返回一个TimeSpan对象。而不是拥有TimeLapse对象的字典,您可以拥有双(which represents seconds)的字典。
var _devices = new Dictionary<string, double>()