【问题标题】:While loop difficultywhile循环难度
【发布时间】:2011-08-10 05:16:50
【问题描述】:

我正在尝试将包含日期的列表 AAA 与日期范围进行比较。我想看看列表中是否存在任何日期范围。如果日期存在,我将列表项复制到另一个列表 BBB,否则我将空值添加到列表 BBB。

我遇到的问题是,对于我的实际代码,我不知道如何不通过 while 循环的错误语句,直到比较结束。

使用下面的代码,它在 while 循环中同时传递 true 和 false,这会伪造所需的结果。我得到的结果是每次出现的时候,我的时间都是假的。简而言之,假设列表包含日期 2010 年 6 月 5 日,日期范围是 2010 年 4 月 5 日到 2010 年 7 月 5 日。所以我将在真实部分创建一个项目,在错误部分创建一个项目,这是错误的。出现的日期可以是真或假的部分。不是两者都有,这样我就创建了两个项目!

我怎样才能获得正确的结果?请提供任何其他方法或建议。

我的代码如下:

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:Date 9Aug,item2:Date 11Aug。

所以我的 tempTask 必须如下: item1:日期 8 月 8 日,taskID:null,ID:null, item2:日期 8 月 9 日,taskID:678,ID:7, item3:日期 10Aug,taskID:null,ID:null, item4: Date11 Aug, taskID:890, ID: 34, item5:日期 8 月 12 日,taskID:null,ID:null, item6:日期 8 月 13 日,taskID:null,ID:null


第二个例子:

我的日期范围如下:8 月 8 日星期一 - 8 月 14 日星期日。 现在我的任务列表如下: item1:Date 9Aug,item2:Date 11Aug,item3:Date 14Aug

所以我的 tempTask 必须如下: item1:日期 8 月 8 日,taskID:null,ID:null, item2:日期 8 月 9 日,taskID:678,ID:7, item3:日期 10Aug,taskID:null,ID:null, item4: Date11 Aug, taskID:890, ID: 34, item5:日期 8 月 12 日,taskID:null,ID:null, item6:日期 8 月 13 日,taskID:null,ID:null, item4:Date14 Aug,taskID:894,ID:74,

【问题讨论】:

  • 为什么不使用bool 表示TimeIsPresent,并将其设置为false
  • 您知道,如果您将TimeIsPresent 定义为bool,则不需要在truefalse 周围加上引号——实际上,您可以使用if (TimeIsPresent)if (!TimeIsPresent) 代替。
  • EndDate 是从哪里来的,为什么还要不断地重新计算 EndDate.AddDays(1)
  • 一开始我使用的是 bool TimeIsPresent,但由于它也不能正常工作,所以我将其更改为字符串。 EndDate 来自我用来比较的日期范围,所以我有开始日期和结束日期。
  • 注意while (EndDate.AddDays(1) != tempDate)不会改变EndDate的值。

标签: c#


【解决方案1】:

我认为你让事情变得比实际情况更困难。据我了解,您正在查看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 日。假设有两个任务 - 日期为 7/3 的任务 1 和日期为 7/12 的任务 2。我希望在 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);
    }
}

【讨论】:

  • 谢谢@Tim,我想你还没有理解我想要实现的目标。使用您的代码,您将遍历列表,直到找到该范围内的日期,这不是我想要的!使用您的代码,一旦您从列表中的范围内找到一个日期,它将停止,之后的所有其他日期都将被忽略。我想要的是将范围内的所有日期(除了 sunday 并且列表 taskList 没有 sunday 的日期)到列表 tempTask 并根据它在列表中的值,它将值复制到 temptask else它将值复制为 null,就像我的示例一样。
  • @learning - 查看我的编辑。在您概述的场景中,如果找到日期,则无需将布尔值设置为 true - 只需评估每个日期,然后添加相应的任务项或空任务项。
  • 感谢@Tim,这些代码都不能解决问题。假设我的任务列表中有日期 2010 年 6 月 5 日 - 星期一、2010 年 7 月 5 日 - 星期二、2010 年 8 月 5 日、2010 年 9 月 5 日 - 星期三(例如虚构的日期)。您的代码仅读取任务列表中 6/5/2010 的值,而其他代码则被排除在外(具有空值)!您的 tempTask 代码结果将仅包含 2010 年 6 月 5 日的值,这不是预期的结果!虽然 tempTask 包含所有其他日期,但它不包含任务列表值!
  • @learning - 见我上面的编辑。您是否正在寻找一个每个日期只有一次的列表,并且该对象具有空 id 或任务 id?如果您可以编辑您的问题并发布您对结果的期望,这可能有助于澄清任何挥之不去的问题。
  • 非常感谢@Tim 的试用,修改给了我第一次发布问题时得到的结果。我需要一个只有一次日期的列表。让我举一个例子。我的日期范围如下:8 月 8 日星期一至 8 月 14 日星期日。现在我的任务列表如下:item1:日期 9Aug,item2:日期 11Aug。所以我的 tempTask 必须如下: item1: Date 8 Aug, taskID: null, ID: null, item2: Date 9 Aug, taskID: 678, ID: 7, item3: Date 10Aug, taskID: null, ID: null, item4 : Date11 Aug, taskID:890, ID: 34, item5: Date 12, taskID: null, ID: null, item6: Date 13, taskID: null, ID: null
【解决方案2】:

我不确定您示例中的 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

中学到的

【讨论】:

  • 很抱歉在一个错误上浪费了您的时间!由于DateTime 是不可变的,因此简单地放置day.AddDays(1) 不会影响循环。我们需要像day = day.AddDays(1) 这样增加日期。我已经更新了我的代码。
  • 非常感谢,您为我提供了解决方案。感谢所有试图帮助我的人!
【解决方案3】:

我发现您的代码有点混乱,但如果我理解您的意图,那么我有一个使用 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);

暂时忽略需要定义的两个部分(datesgetTasksForDate),查询的工作原理是从头到尾遍历每个日期并选择该日期的任务(从 @ 987654328@ 或“虚拟”任务(如果该日期不存在),然后过滤掉周日的任何“虚拟”任务。然后将任务添加到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,以确保日期没有时间分量。

如果您想进一步解释,请大声喊叫。

【讨论】:

    【解决方案4】:

    如果我理解你想要做什么,我会改变你这样做的方式。首先,我会在您的范围内找到具有一个或多个相关任务的所有日期(并将它们放在字典中以便能够让他们知道日期),然后我将创建 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 });
                    }
                }
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-13
      • 2017-04-06
      • 1970-01-01
      • 2015-11-24
      • 1970-01-01
      • 2019-03-26
      • 1970-01-01
      • 2016-04-24
      相关资源
      最近更新 更多