【问题标题】:Find next closest date查找下一个最近的日期
【发布时间】:2014-03-05 20:16:06
【问题描述】:

我有一些日期当前存储为字符串列表。

例如:

List<string> dates = new List<string>();
dates.Add("1/10/14");
dates.Add("2/9/14");
dates.Add("1/15/14");
dates.Add("2/3/14");
dates.Add("2/15/14");

(日期为mm/dd/yy格式)

我将接受用户的输入(也采用mm/dd/yy 格式),但作为字符串。

现在,我想在数组中查找用户输入日期之后最接近的日期。

例如,如果用户输入"1/13/14",则输出应为"1/15/14"。 如果用户输入"2/5/14",则下一个最接近的日期是"2/9/14"。 但是如果用户输入的日期晚于最后一个日期(比如"3/1/14",它仍然会返回数组中的最后一个日期"2/15/14"

我知道在某些时候您必须转换为 DateTime 类型,但我无法弄清楚找到此类日期的逻辑。

【问题讨论】:

  • 将字符串解析为日期与在日期列表中查找最近的日期是完全不同的问题。分开处理。首先将这些日期解析为DateTime 对象。然后,一旦你有了它,就在List&lt;DateTime&gt; 中寻找最近的日期。
  • mm 分钟,MMM 几个月..
  • 为什么首先将日期存储为字符串?
  • @user3320572 然后将它们解析为DateTime 对象。在尝试解决查找最近日期的问题时,它们来自文件不应该是相关的。
  • 考虑这一点:如果您想要“下一个”日期,则该日期必须大于您拥有的日期。然后,当您发现所有日期都大于您所拥有的日期时,您需要其中最小的一个。使用 LINQ 的简单实现(假设列表包含 DateTime 而不是字符串):dates.Where(dt =&gt; dt &gt; theOneIHave).Min()。现在,如果您有很多日期,首先抓取所有较大的日期,然后检索最小的日期,可能效果不佳。在这种情况下,我可能会对列表进行排序,然后使用二进制搜索来找到最接近(但更大)的值。

标签: c# datetime datetime-format


【解决方案1】:
List<string> dates = new List<string>();
            dates.Add("1/10/14");
            dates.Add("2/9/14");
            dates.Add("1/15/14");
            dates.Add("2/3/14");
            dates.Add("2/15/14");

            var allDates = dates.Select(DateTime.Parse).OrderBy(d=>d).ToList();
            var inputDate = DateTime.Parse("1/13/14");

            var closestDate = inputDate >= allDates.Last()
                ? allDates.Last()
                : inputDate <= allDates.First()
                    ? allDates.First()
                    : allDates.First(d => d >= inputDate);

现在我只是在解析字符串,但你应该单独处理它。这是简单的普通 LINQ,您也可以进行二分搜索。

【讨论】:

    【解决方案2】:

    这是一个使用二分搜索的解决方案。

    你需要有一个DateTimes 的列表,毫无疑问。将它们保留为strings 毫无意义,如果必须,请在进入列表的过程中解析它们。您可以使用 LINQ 转换列表中的所有元素,但这是您能够相互比较日期的唯一方法。

    查看BinarySearch 的页面,了解为什么我在返回值上使用按位运算符。

    //build list of random dates
    Random r = new Random();
    var dates = new List<DateTime>();
    for (int i = 0; i < 10; i++)
    {
        dates.Add(new DateTime(2014, r.Next(1,13), r.Next(1,28)));
    }
    
    //sort list (if you don't do this, you'll most likely get the wrong answer)
    dates.Sort();
    
    //get input
    string input = "1/13/14";
    DateTime inputDate = DateTime.Parse(input);
    
    //find nearest
    var result = dates.BinarySearch(inputDate);
    DateTime nearest;
    
    //get match or next in list.
    if(result >= 0)
        nearest = dates[result];
    else if (~result == dates.Count )
        nearest =dates.Last();
    else
        nearest = dates[~result];
    

    如果您需要找到真正最接近的,请使用它来代替最后一个 if 块。

    //get match, or true nearest date in list
    if(result >= 0)                   //date was found! Use that index.
        nearest = dates[result];
    else if (~result == 0)            //date not found, smaller than any item in the list. use first index.
        nearest = dates.First();
    else if(~result == dates.Count)   //date was not found, and is greater than all items. Use last index.
        nearest = dates.Last();
    else                              //date not found, somewhere in the middle of the list. find the nearest date                              
    {
        var daysAfter = dates[~result].Subtract(inputDate);      //date after input
        var daysBefore = inputDate.Subtract(dates[~result - 1]); //date before input
        if(daysAfter < daysBefore)
            nearest = dates[~result];
        else
            nearest = dates[~result - 1];
    }
    

    【讨论】:

    • 这个问题似乎要求“下一个更高”,而不是“最近”。这意味着您只需要为&gt;= Count 保护~result
    • 哦,我完全忽略了这一点。谢谢你。我什至对别人的代码发表了评论。哦!
    • 我没有看到,但我添加了我自己的。可能和你打算做的一样。如果它更好,请继续编辑。这让问题变得更容易(更不用说更高效了)。
    • 这个将在目标日期之后失败,然后是最新的数组值。 (~结果 == 计数)。
    • 刚刚注意到,正如您发布的那样,现在应该很好了。感谢您的帮助。
    【解决方案3】:
    DateTime searchDate = new DateTime(2014,03,01);
    
    var orderedDates = dates
    .Select(d => DateTime.ParseExact(d, "M/d/yy", CultureInfo.InvariantCulture))
    .OrderBy(d => d).ToList();
    
    var result = orderedDates.FirstOrDefault(d => d > searchDate);
    if (result == default(DateTime))
      result = orderedDates.Last();
    

    【讨论】:

    • 这适用于 Price Is Right 规则(最接近但不超过),但它找不到真正最接近的,对吧?
    【解决方案4】:

    这样的?

    List<string> dates   = YourListOfStringsHere() ; // list of strings in MM/dd/yyyy form.
    DateTime desiredDate = new DateTime(2014,2,27) ;
    DateTime foundDate   = dates
                           .Select( x => DateTime.ParseExact(x,"MM/dd/yyyy",CultureInfo.CurrentCulture))
                           .Where( x => x >= desiredDate.Date )
                           .Min()
                           ;
    

    为什么要将日期/时间值存储为字符串,这超出了我的理解。当你加载它们时,为什么不转换它们呢?这样,它们更容易操作,你知道你有干净的数据。一切都变得简单多了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-22
      • 1970-01-01
      相关资源
      最近更新 更多