而循环难度

本文关键字:循环 | 更新日期: 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);
    }
}

我不确定什么是EndDatetempDate和你的例子中的其他一些东西。但是,如果您尝试遍历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));

只要StartDateEndDate之前,你现在就会有一个日期列表,从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 });
                }
            }
        }