而循环难度
本文关键字:循环 | 更新日期: 2023-09-27 18:05:08
我正在尝试比较包含日期和日期范围的列表AAA。我想看看日期的范围是否存在于列表中。如果存在日期,则将列表项复制到另一个列表BBB中,否则将空值添加到列表BBB中。
我遇到的问题是,在我的实际代码中,我不知道如何不通过while循环的false语句,直到它达到比较的结束。
在下面的代码中,它在while循环中传递了true和false,从而伪造了所需的结果。我得到的结果是,对于每一个存在的时间,我都有同样的假时间。简而言之,假设列表包含日期6/5/2010,日期范围为4/5/2010至7/5/2010。所以我将在true部分创建一个项目,在FALSE部分创建一个项目,这是错误的。出现的日期可以是真部分,也可以是假部分。不是两个都有,这样我就创建了两个项目!我怎样才能达到正确的结果?有其他方法或建议吗?
我的代码如下:DateTime StartDate;
DateTime EndDate;
Datetime tempDate = StartDate;
List<DateTime> dateToEvaluate;
bool TimeIsPresent = false;
foreach (var tempItem in TaskList)
{
while (EndDate.AddDays(1) != tempDate)
{
if (tempItem.Date[0] == tempDate)
{
TimeIsPresent = True;
break;
}
else
{
if (TimeIsPresent == False)
{
if (!(tempDate.DayOfWeek == DayOfWeek.Sunday)
{
dateToEvaluate = new List<DateTime>();
dateToEvaluate.Add(tempDate);
tempTask.Add(new GroupedTask { ID = null,
TaskID = null,
Date = dateToEvaluate });
}
}
}
tempDate = tempDate.AddDays(1);
}
if (TimeIsPresent == True)
{
tempTask.Add(new GroupedTask { ID = tempItem.ID,
TaskID = tempItem.TaskID,
Date = tempItem.Date });
TimeIsPresent = false;
}
}
让我给你举个例子。我的日期范围如下:8月8日星期一至8月14日星期日。现在我的任务列表如下:item1:日期8月9日,item2:日期8月11日。
所以我的tempTask必须如下所示:item1: Date 8 Aug, taskID: null, ID: null,item2:日期8月9日,任务编号:678,ID: 7,item3: Date 10Aug, taskID: null, ID: null,item4: Date11 Aug, taskID:890, ID: 34,item5: Date 12 Aug, taskID: null, ID: null,item6: Date 13 Aug, taskID: null, ID: null
第二个例子:
我的日期范围如下:星期一8月8日-星期日8月14日。现在我的任务列表如下:item1:日期8月9日,item2:日期8月11日,item3:日期8月14日
所以我的tempTask必须如下所示:item1: Date 8 Aug, taskID: null, ID: null,item2:日期8月9日,任务编号:678,ID: 7,item3: Date 10Aug, taskID: null, ID: null,item4: Date11 Aug, taskID:890, ID: 34,item5: Date 12 Aug, taskID: null, ID: null,item6: Date 13 Aug, taskID: null, ID: null,
我觉得你把事情弄得比实际情况更困难了。按照我的理解,你是在取TaskList
中的每一项,看看日期是否在某个范围内。如果有,你就把它添加到另一个列表中,然后转到下一个项目,否则你就在另一个列表中添加一个空白条目,然后继续检查。
如果我的理解是正确的,试试这个:
根据OP的注释编辑
代码现在遍历TaskList
中每个项目的整个范围,并添加一个带有日期的空对象或相应的日期任务。
在这种情况下,不需要使用bool
来确定是否存在日期。
// Note that you'll have to assign values to StartDate and EndDate, otherwise you'll get
// a Null Reference Exception
DateTime StartDate;
DateTime EndDate;
Datetime tempDate = StartDate;
List<DateTime> dateToEvaluate;
foreach (var tempItem in TaskList)
{
// Reset tempDate to the starting date before each loop
tempDate = StartDate;
while (EndDate.AddDays(1) != tempDate)
{
if (tempDate.DayOfWeek != DayOfWeek.Sunday)
{
if (tempItem.Date[0] == tempDate)
{
tempTask.Add(new GroupedTask { ID = tempItem.ID,
TaskID = tempItem.TaskID,
Date = tempItem.Date });
}
else
{
dateToEvaluate = new List<DateTime>();
dateToEvaluate.Add(tempDate);
tempTask.Add(new GroupedTask { ID = null,
TaskID = null,
Date = dateToEvaluate });
}
}
tempDate = tempDate.AddDays(1);
}
}
编辑添加
假设一个2周的范围,7/1从周一开始到7/14。假设有两个任务——任务1的日期是7月3日,任务2的日期是7月12日。我希望在tempTask中有以下内容:
26个元素(两个任务项各有13个日期),除两个任务项各有一个外,所有元素的ID都为空。
你真的想要一个没有重复的合并列表吗?也就是说,在我的例子中,将有13个元素,其中2个将具有非空id ?如果两个或两个以上的任务有相同的日期会发生什么?
我确实发现了一个错误,因为我没有在每个循环之前将tempDate重置为开始。
编辑基于新的理解
好的,所以您试图获得第二个列表,该列表具有给定范围内的所有日期,并且GroupedTask
对象将是该日期的现有GroupedTask
,或者是该日期的空GroupedTask
,如果没有匹配。
我建议你看看Enigmativity的答案,因为这可能是一个更优雅的解决方案(我还没有详细研究过),但这里有另一种方法。最大的变化是我翻转了while循环和foreach循环。
// Note that you'll have to assign values to StartDate and EndDate, otherwise you'll get
// a Null Reference Exception
DateTime StartDate;
DateTime EndDate;
// Declare an instance of GroupedTask for use in the while loop
GroupedTask newTask;
Datetime tempDate = StartDate;
// Loop through the entire range of dates
while (EndDate.AddDays(1) != tempDate)
{
// You included Sundays in your example, but had earlier indicated they
// weren't needed. If you do want Sundays, you can remove this outer if
// block
if (tempDate.DayOfWeek != DayOfWeek.Sunday)
{
// Create a "null" GroupedTask object
// The Date property in GroupedTask appears to be a List<DateTime>,
// so I chose to initialize it along with the other properties.
newTask = new GroupedTask() { ID = null,
TaskID = null,
Date = new List<DateTime>() { tempDate }};
// For each date in the range, check to see if there are any tasks in the TaskList
foreach (var tempItem in TaskList)
{
// If the current item's date matches the current date in the range,
// update the newTask object with the current item's values.
// NOTE: If more than one item has the current date, the last one in
// will win as this code is written.
if (tempItem.Date[0] == tempDate)
{
newTask.ID = tempItem.ID;
newTask.TaskID = tempItem.TaskID;
newTask.Date = tempItem.Date;
}
}
// Add the newTask object to the second list
tempTask.Add(newTask);
}
}
我不确定什么是EndDate, tempDate和你的例子中的其他一些东西。但是,如果您尝试遍历DateRange并检查特定日期的存在,那么您可以考虑以下示例:
static void yourFunction()
{
//
//Some Stuffs
//
foreach (var tempItem in TaskList)
{
if (DateRange.Contains(tempItem.Date[0]))
{
//Do Task
}
else
{
//Do Task
}
}
//
//Some Stuffs
//
}
public static IEnumerable<DateTime> DateRange
{
get
{
for (DateTime day = startDate; day < EndDate; day = day.AddDays(1))
{
yield return day;
}
}
}
在属性中封装日期范围的想法是Jon Skeet,我从他的书C# in Depth
我发现你的代码有点混乱,但如果我理解你的意图,那么我有一个解决方案,你使用LINQ。我的方法一开始可能有点令人困惑,但我很乐意帮助你解决这个问题。
我的理解是,你有一个日期范围,你想要创建一个GroupedTask
对象的匹配列表,你将从现有的TaskList
中为范围内的每个匹配日期获取对象,或者如果没有匹配,创建一个"虚拟"实例。
我假设您已经定义了一个StartDate
变量以及您在问题中使用的EndDate
变量。
我的解决方案(我已经测试过了)是这样的:
var query =
from d in dates
from t in getTasksForDate(d)
where (t.ID != null) || (d.DayOfWeek != DayOfWeek.Sunday)
select t;
tempTask.AddRange(query);
暂时忽略需要定义的两个部分(dates
&getTasksForDate
)查询的工作方式是从开始到结束运行每个日期,并选择该日期的任务(从TaskList
或"虚拟"任务,如果日期不存在),然后过滤掉任何落在星期日的"虚拟"任务。然后将这些任务添加到tempTask
列表中。
现在为缺失的部分。
获取dates
列表,只需这样做:
var days = EndDate.Date.Subtract(StartDate.Date).Days + 1;
var dates =
Enumerable
.Range(1 - days, days)
.Select(d => EndDate.AddDays(d));
只要StartDate
在EndDate
之前,你现在就会有一个日期列表,从StartDate
开始,到EndDate
结束。
getTasksForDate
是比较棘手的部分。
您需要首先将TaskList
列表转换为查找函数,该函数将任何日期转换为该日期的GroupedTask
对象列表。使用LINQ很容易:
var lookup = TaskList.ToLookup(x => x.Date[0].Date, x => new GroupedTask()
{
ID = x.ID,
TaskID = x.TaskID,
Date = x.Date,
});
接下来,您需要创建getTasksForDate
函数,该函数将接受一个日期,并从日期查找中返回GroupedTask
列表,或者如果没有该日期的任务,则返回单个"虚拟"GroupedTask
对象。
Func<DateTime, IEnumerable<GroupedTask>> getTasksForDate = d =>
{
return lookup[d].DefaultIfEmpty(new GroupedTask()
{
ID = null,
TaskID = null,
Date = new List<DateTime>() { d, },
});
};
。
如果您想根据TaskList
的实际值定义StartDate
和/或EndDate
,您可以使用以下代码:
var StartDate = TaskList.Select(t => t.Date[0].Date).Min();
var EndDate = TaskList.Select(t => t.Date[0].Date).Max();
我在大多数DateTime
引用之后使用.Date
,以确保日期没有时间成分。
如果你想要进一步的解释就大声说出来。
如果我明白你想做什么,我会改变你这样做的方式。首先,我将找到您的范围内具有一个或多个相关任务的所有日期(并将它们放入Dictionary中,以便能够让它们知道日期),然后我将创建tempTask。像这样:
DateTime StartDate;
DateTime EndDate;
DateTime tempDate = StartDate;
List<DateTime> dateToEvaluate;
Dictionary<DateTime, List<Task>> dateTaskDict = new Dictionary<DateTime, List<Task>>();
bool TimeIsPresent = false;
foreach (Task tempItem in TaskList)
{
while (EndDate.AddDays(1) != tempDate)
{
if (tempItem.Date[0] == tempDate)
{
List<Task> tasksForDate;
if (!dateTaskDict.TryGetValue(tempDate, out tasksForDate))
{
tasksForDate = new List<Task>();
dateTaskDict[tempDate] = tasksForDate;
}
tasksForDate.Add(tempItem);
break;
}
tempDate = tempDate.AddDays(1);
}
}
tempDate = StartDate;
while (EndDate.AddDays(1) != tempDate)
{
List<Task> tasks;
if (dateTaskDict.TryGetValue(tempDate, out tasks))
{
foreach (Task aTask in tasks)
tempTask.Add(new GroupedTask { ID = aTask.ID,
TaskID = aTask.TaskID,
Date = tempDate });
}
else
{
if (tempDate.DayOfWeek != DayOfWeek.Sunday)
{
tempTask.Add(new GroupedTask { ID = null
TaskID = null,
Date = tempDate });
}
}
}