在C#中,将一个日期时间集合聚合并转换为另一个日期时间集合的最佳方法是什么?
我在C#中有一个小小的日历工具,我正在试图弄清楚如何从一个DateTime对象数组转换到另一个DateTime对象数组。详情如下: 我从DateTime对象的集合开始在C#中,将一个日期时间集合聚合并转换为另一个日期时间集合的最佳方法是什么?,c#,datetime,collections,C#,Datetime,Collections,我在C#中有一个小小的日历工具,我正在试图弄清楚如何从一个DateTime对象数组转换到另一个DateTime对象数组。详情如下: 我从DateTime对象的集合开始 IEnumerable<DateTime> slots = GetSlots(); IEnumerable slots=GetSlots(); 其中,每个DateTime表示一个可用时段的开始时间(想想日历中的开放时段)所有时段都为30分钟这是给定的。例如: var slots = new List<Dat
IEnumerable<DateTime> slots = GetSlots();
IEnumerable slots=GetSlots();
其中,每个DateTime表示一个可用时段的开始时间(想想日历中的开放时段)所有时段都为30分钟这是给定的。例如:
var slots = new List<DateTime>()
slots.Add(DateTime.Today + new TimeSpan(5,00, 0));
slots.Add(DateTime.Today + new TimeSpan(9,00, 0));
slots.Add(DateTime.Today + new TimeSpan(9,30, 0));
slots.Add(DateTime.Today + new TimeSpan(10,00, 0));
slots.Add(DateTime.Today + new TimeSpan(10,30, 0));
slots.Add(DateTime.Today + new TimeSpan(11,00, 0));
slots.Add(DateTime.Today + new TimeSpan(16,30, 0));
var slots=新列表()
slots.Add(DateTime.Today+newtimespan(5,00,0));
slots.Add(DateTime.Today+newtimespan(9,00,0));
slots.Add(DateTime.Today+newtimespan(9,30,0));
slots.Add(DateTime.Today+newtimespan(10,00,0));
slots.Add(DateTime.Today+newtimespan(10,30,0));
slots.Add(DateTime.Today+newtimespan(11,00,0));
slots.Add(DateTime.Today+newtimespan(16,30,0));
在上面的例子中,这意味着我是自由的:
IEnumerable<DateTime> aggregateArray = MergeIntoLargerSlots(slots, 120);
IEnumerable aggregateArray=mergeinto大插槽(插槽,120);
基本上,我必须在上面的插槽数组中循环,并“合并”排列在每个插槽旁边的项目,以生成更大的存储桶。如果任何合并项的长度为2小时,则应在结果数组中显示为一个条目。使用上面的示例,生成的aggregateArray在集合中有2个项目,它们的时间为:
- 上午9点(因为我有一个从上午9点到11点(120分钟)的空闲时间)
- 上午9:30(因为我有一个从上午9:30-11:30(120分钟)的空闲时间)
我正在努力弄清楚这个MergeIntoLargerSlots函数是如何工作的,所以我希望能得到一些解决这个问题的建议。假设您的原始列表已排序(如果未排序,则按原样排序),您可以循环查看原始列表并检查相邻项是否连续(即开始时间的距离是否正好为30分钟)。始终跟踪当前连续时间段系列中的第一项-一旦到达其中四个(4个连续30分钟时间段加起来可能是两小时时间段;其他时间段大小显然需要不同的因素),将新的两小时时间段保存到结果列表中,并将引用更新到当前连续项目系列的开头
未经测试,请将此视为伪代码:
var twoHourSlots = new List<DateTime>();
int consecutiveSlotsCount = 0;
DateTime? previousSlot;
foreach (DateTime smallSlotStart in slots) {
if (previousSlot.HasValue) {
if (smallSlotStart - previousSlot.Value == new TimeSpan(0, 30, 0)) {
consecutiveSlotsCount++;
} else {
consecutiveSlotsCount = 0;
}
}
if (consecutiveSlotsCount == 4) {
twoHourSlots.Add(smallSlotStart - new TimeSpan(1, 30, 0));
consecutiveSlots = 0;
previousSlot = null;
} else {
previousSlot = smallSlotStart;
}
}
var twowhourslots=new List();
int continuenceslotscont=0;
日期时间?上一个时隙;
foreach(插槽中的DateTime smallSlotStart){
if(上一个slot.HasValue){
if(smallSlotStart-previousSlot.Value==newtimespan(0,30,0)){
连续LotusScont++;
}否则{
连续LOTSCONT=0;
}
}
如果(连续的LOTSCONT==4){
添加(smallSlotStart-newtimespan(1,30,0));
连续批次=0;
previousSlot=null;
}否则{
previousSlot=smallSlotStart;
}
}
需要注意的一些事项:
- 我正在对
值使用算术运算符。请查看以了解更多信息;它们可以做一些方便的事情,通常可以让您自动处理值DateTime
- 我多次使用a。这就是三个数字的含义
- 我已经声明了
,一个跟踪最后查看的插槽(与当前插槽进行比较)的变量,称为previousSlot
(如果不确定可为空的类型,请再次检查).这是因为在DateTime?
循环的第一次迭代中,没有以前的插槽可供查看,循环的行为必须不同foreach
- 同样地,
设置为previousSlot
当我们找到一个2小时的时隙时,因为找到的2小时时隙的最后30分钟时隙不应计入下一个可能的2小时时隙null
- 一旦找到四个连续的30分钟时段,则从最后一个时段的开始减去一小时三十分钟。这是因为最后一个30分钟时段开始后的三十分钟将是最终2小时时段的一部分
public List<DateTime> MergeIntoLargerSlots(List<DateTime> slots, int minutes)
{
int count = minutes/30;
List<DateTime> retVal = new List<DateTime>();
foreach (DateTime slot in slots)
{
DateTime end = slot.AddMinutes(minutes);
if (slots.Where(x => x >= slot && x < end).Count() == count)
{
retVal.Add(slot);
}
}
return retVal;
}
公共列表合并到更大的插槽(列表插槽,整数分钟)
{
整数计数=分钟/30;
List retVal=新列表();
foreach(插槽中的日期时间插槽)
{
DateTime end=slot.AddMinutes(分钟);
if(slots.Where(x=>x>=slot&&x
下面是我解决问题方法的简要说明;我把分钟数和插槽列表都记下来。我加上分钟数得到一个结束时间,这个时间给了我一个范围。从那里,我使用Where
操作符来产生和IEnumerable
来自slots
的插槽。我将结果与count我通过执行minutes/slotLength
得到的变量,如果数字匹配,那么您就有了必要的插槽
private List<DateTime> MergeArray(List<DateTime> slots, int minutes)
{
var segments = minutes / InitialSegment;
var validSegments = new List<DateTime>();
foreach (var slot in slots.OrderBy(x => x))
{
var validSegment = true;
for (var i = 0; i < segments-1; i++)
{
var next = slot.AddMinutes(InitialSegment * (i + 1));
if (slots.All(x => x != next))
{
validSegment = false;
break;
}
}
if (validSegment)
validSegments.Add(slot);
}
return validSegments;
}
public sealed class TimeInterval
{
public DateTime Start { get; private set; }
public DateTime End { get { return Start.AddMinutes(Duration); } }
public double Duration { get; private set; }
public TimeInterval(DateTime start, int duration)
{
Start = start;
Duration = duration;
}
public IEnumerable<TimeInterval> Merge(TimeInterval that)
{
if(that.Start >= this.Start && that.Start <= this.End)
{
if(that.End > this.End)
Duration += (that.Duration - (this.End - that.Start).TotalMinutes);
yield return this;
}
else
{
yield return this;
yield return that;
}
}
}
//the `spans` parameter must be presorted
public IEnumerable<TimeInterval> Merge(IEnumerable<TimeInterval> spans, int duration)
{
var stack = new Stack<TimeInterval>();
stack.Push(spans.First());
foreach (var span in spans.Skip(1))
foreach(var interval in stack.Pop().Merge(span)) //this enumeration is guaranteed to have either one element or two elements.
stack.Push(interval);
return from interval in stack where interval.Duration >= duration select interval;
}