C#-将具有日期的行分组为具有时间持续时间的块
这有点难以解释。我有一个包含计划信息的数据表。每行代表一个带有开始日期/时间和结束日期/时间的计划。我需要对这些进行分组,以便总体开始到结束时间与给定的持续时间相匹配 例如,我的数据表中可能有以下内容:C#-将具有日期的行分组为具有时间持续时间的块,c#,sql,C#,Sql,这有点难以解释。我有一个包含计划信息的数据表。每行代表一个带有开始日期/时间和结束日期/时间的计划。我需要对这些进行分组,以便总体开始到结束时间与给定的持续时间相匹配 例如,我的数据表中可能有以下内容: Schedule1: Start - 9:00AM, End - 9:30AM Schedule2: Start - 9:30AM, End - 10:00AM Schedule3: Start - 10:00AM, End - 10:30AM Schedule4: Start - 10:30A
Schedule1: Start - 9:00AM, End - 9:30AM
Schedule2: Start - 9:30AM, End - 10:00AM
Schedule3: Start - 10:00AM, End - 10:30AM
Schedule4: Start - 10:30AM, End - 11:00AM
现在,如果给我一个持续时间值60分钟,那么我需要能够生成以下输出:
Block1: Schedules(1,2): 9:00AM - 10:00AM
Block2: Schedules(2,3): 9:30AM - 10:30AM
Block3: Schedules(3,4): 10:00AM - 11:00AM
但是,如果持续时间改为120分钟,则我需要生成以下内容:
Block1: Schedules(1,2,3,4): 9:00AM - 11:00AM
如果需要澄清,请告诉我。我需要用C语言编写一个方法来进行转换。请帮我解决这个问题,因为我已经花了很长时间在这个问题上。您选择用C#还是SQL来解决这个问题部分取决于数据的规模。假设我们使用的时间范围相对较少(比如<10),那么将所有时间都拉入内存并在C#中查找块是合理的 鉴于以下类别:
public class Schedule {
public int ID { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public int Minutes { get; set; }
}
public class ScheduleBlock : Schedule {
public List<Schedule> Schedules { get; set; }
}
为什么您需要在C#中执行此操作,而不是编写SQL查询来获取结果?要扩展SpaceghostAli的观点,您是否使用实体框架来执行此查询?如果你使用的是ADO,那么它将是直接的SQL。我想我可以用SQL来实现……我只是觉得用c#更简单。如果你有一个sql的解决方案,我也可以使用它。如果你要花那么多的精力去寻找答案,至少要让它变得优雅。尝试使用递归和PLinq之类的工具。@Tsabo:请随意提供一个替代解决方案。这是我的午餐时间练习:我确实考虑过递归,但我想不出一个好的算法。使用PLinq可能会使代码稍微更有效率,但不会改变算法。例如,为ScheduleBlock提供对所有可用计划的引用,并使用递归方法查找所有可能的延续。每个步骤都会出现深度克隆ScheduleBlock,这是一个潜在的结果。使用PLinq在所有时间表上启动该方法。@mellamokb-非常感谢您抽出时间回答我的问题。你的解决方案对我真的很有帮助。不管它是不是递归,任何有效的方法都可以。如果我有任何问题或者有什么我不明白的,我会回复你。
public List<ScheduleBlock> CombineAllSchedules(List<Schedule> origschedules, out int added)
{
added = 0;
var schedules = new List<ScheduleBlock>();
foreach (var s in origschedules) {
var snew = new ScheduleBlock { Schedules = new List<Schedule> { s }, Start = s.Start, End = s.End, Minutes = s.Minutes };
schedules.Add(snew);
}
for (var i = 0; i < schedules.Count; i++) {
var s = schedules[i];
var matchstart = schedules.Where (s2 => s2.End == s.Start).ToList();
var matchend = schedules.Where (s2 => s2.Start == s.End).ToList();
foreach (var s2 in matchstart) {
var newschedule = CombineSchedules(s2, s);
if (!schedules.Any (sc => sc.Start == newschedule.Start && sc.End == newschedule.End)) {
schedules.Add(newschedule);
added++;
}
}
foreach (var s2 in matchend) {
var newschedule = CombineSchedules(s, s2);
if (!schedules.Any (sc => sc.Start == newschedule.Start && sc.End == newschedule.End)) {
schedules.Add(newschedule);
added++;
}
}
}
return schedules;
}
public ScheduleBlock CombineSchedules(Schedule s1, Schedule s2)
{
var schedules = new List<Schedule>();
if (s1 is ScheduleBlock) schedules.AddRange(((ScheduleBlock)s1).Schedules);
else schedules.Add(s1);
if (s2 is ScheduleBlock) schedules.AddRange(((ScheduleBlock)s2).Schedules);
else schedules.Add(s2);
var s = new ScheduleBlock {
Schedules = schedules,
Start = s1.Start, End = s2.End, Minutes = s1.Minutes + s2.Minutes
};
return s;
}
public List<ScheduleBlock> FindBlocks(List<Schedule> schedules, int blockLength)
{
int added;
var combinedSchedules = CombineAllSchedules(schedules, out added);
var result = combinedSchedules.Where (s => s.Minutes == blockLength).ToList();
return result;
}
var schedules = new List<Schedule> {
new Schedule { ID = 1, Start = DateTime.Parse("09:00 AM"), End = DateTime.Parse("09:30 AM") },
new Schedule { ID = 2, Start = DateTime.Parse("09:30 AM"), End = DateTime.Parse("10:00 AM") },
new Schedule { ID = 3, Start = DateTime.Parse("10:00 AM"), End = DateTime.Parse("10:30 AM") },
new Schedule { ID = 4, Start = DateTime.Parse("10:30 AM"), End = DateTime.Parse("11:00 AM") },
};
foreach (var s in schedules) {
s.Minutes = (int)(s.End - s.Start).TotalMinutes;
}
Console.WriteLine("60 Minute Blocks");
Console.WriteLine("----------------");
var blocks = FindBlocks(schedules, 60);
var blockId = 1;
foreach (var block in blocks) {
var output = "Block" + blockId +
": Schedules(" + string.Join(",", block.Schedules.Select (s => s.ID)) + "): " +
block.Start.ToString("h:mmtt") + " - " + block.End.ToString("h:mmtt");
Console.WriteLine(output);
blockId++;
}
Console.WriteLine();
Console.WriteLine("120 Minute Blocks");
Console.WriteLine("----------------");
blocks = FindBlocks(schedules, 120);
blockId = 1;
foreach (var block in blocks) {
var output = "Block" + blockId +
": Schedules(" + string.Join(",", block.Schedules.Select (s => s.ID)) + "): " +
block.Start.ToString("h:mmtt") + " - " + block.End.ToString("h:mmtt");
Console.WriteLine(output);
blockId++;
}
60 Minute Blocks
----------------
Block1: Schedules(1,2): 9:00AM - 10:00AM
Block2: Schedules(2,3): 9:30AM - 10:30AM
Block3: Schedules(3,4): 10:00AM - 11:00AM
120 Minute Blocks
----------------
Block1: Schedules(1,2,3,4): 9:00AM - 11:00AM