【问题标题】:Fastest way to check a List<T> for a date检查 List<T> 日期的最快方法
【发布时间】:2010-04-10 13:40:51
【问题描述】:

我有一个机器工作的日期列表,但它不包括机器停机的日期。我需要创建工作天数和未工作天数的列表。我不确定执行此操作的最佳方法。我已经开始递增一个范围的所有天数,并通过每次迭代整个列表来检查日期是否在列表中。我正在寻找一种更有效的方法来查找日期。

class machineday
{
 datetime WorkingDay;
}

class machinedaycollection : List<machineday>
{
public List<TimeCatEvent> GetAllByCat(string cat)
{
  _CategoryCode = cat;


  List<machineday> li = this.FindAll(delegate(machinedaydummy) { return true; });
  li.Sort(sortDate);
  return li;
}

int sortDate(machinedayevent1, machinedayevent2)
{
  int returnValue = -1;
  if (event2.date < event1.date)
  {
    returnValue = 0;
  }
  else if (event2.date == event1.date)
  {
    //descending
    returnValue = event1.date.CompareTo(event2.date);
  }
  return returnValue;
}
}

【问题讨论】:

    标签: c# generics .net-2.0 generic-list


    【解决方案1】:

    对日期进行排序并在递增计数器的同时迭代结果列表。每当计数器与当前列表元素不匹配时,您就会发现列表中缺少日期。

    List<DateTime> days = ...;
    days.Sort();
    DateTime dt = days[0].Date;
    for (int i = 0; i < days.Length; dt = dt.AddDays(1))
    {
        if (dt == days[i].Date)
        {
            Console.WriteLine("Worked: {0}", dt);
            i++;
        }
        else
        {
            Console.WriteLine("Not Worked: {0}", dt);
        }
    }
    

    (假设列表中没有重复的日期。)

    【讨论】:

    • 这不是一个好的解决方案,因为它需要 15 行才能达到 1 或 2 行。查看 Marcelo Cantos 的基于集合的解决方案。尽管 except 方法在您的 .net 版本中可能不可用,但您可以以可重用的方式自己编写它。
    • @usr:你看过标签了吗?这是在 .NET 2.0 中实际工作的唯一 解决方案。
    【解决方案2】:

    使用 LINQ 的 Enumerable.Except 扩展方法构建一个有效日期列表并从中减去您的机器日集合。像这样的:

    IEnumerable<DateTime> dates = get_candidate_dates();
    var holidays = dates.Except(machinedays.Select(m => m.WorkingDay));
    

    get_candidate_dates() 方法甚至可以是一个迭代器,它可以动态生成某个范围内的所有日期,而不是所有日期的预存储列表。

    Enumerable 的方法相当聪明,通常在性能方面做得不错,但如果您想要尽可能快的算法,这将取决于您计划如何使用结果。

    【讨论】:

    • 这个问题可以选择 LINQ 吗?
    • 也许不是(我刚刚注意到 .Net 2 标记),但 Enumerable 可以从 .Net 2.0 访问,尽管语法更笨拙。您只需添加对 System.Core 程序集的引用。
    【解决方案3】:

    对不起,伙计们,但我不太喜欢你的解决方案。 我认为你应该用你的日期创建一个 HashTable。您可以通过只在工作日进行一次交互来做到这一点。

    然后,如果日期存在或不存在,您可以使用

    myHashTable.ContainsKey(day); // this is efficient
    

    简单、优雅、快速。

    我认为您的解决方案使用指数时间,这是线性时间或对数时间(这实际上是一件好事)。

    【讨论】:

    • 常量时间和内存,但是内存常量是HUGE,这是一件很糟糕的事情。
    • @Ben:不一定,取决于性能是否是更关键的问题。更好的性能通常是以内存等其他资源为代价的。
    • 有趣,我从没想过这个方向
    • 巨大?保守地说,使用大约 1mb 的内存,您可以存储 45 年的日期。处理简单数据类型时,内存通常不再是问题。这在 15 年前就不同了,还记得那些日子吗???? 640k的机器!!
    • 问题是您必须进行多少次搜索才能平衡首先设置散列数据结构所花费的时间。仅列出状态在“服务中”和“维护中”之间变化的日期的排序密集结构将非常快速地使用二分搜索。
    【解决方案4】:

    假设列表已排序并且机器大部分时间都在“工作”,您可以通过按月分组日期并跳过其间的日期来避免遍历所有日期。像这样的东西(你需要清理):

    int chunksize = 60; // adjust depending on data
    machineday currentDay = myMachinedaycollection[0];
    
    for (int i = 0; i < myMachinedaycollection.Count; i += chunksize)  
    {  
        if (currentDay.WorkingDay.AddDays(chunksize) != myMachinedaycollection[i + chunksize].WorkingDay)  
        {
            // write code to iterate through current chunk and get all the non-working days  
        }
        currentDay = myMachinedaycollection[i + chunksize];  
    }  
    

    【讨论】:

      【解决方案5】:

      我怀疑你想要一份工作天数和不工作天数的列表。

      您的问题标题表明您想知道系统是否在特定日期启动。计算正常运行时间百分比似乎也是合理的。这些都不需要构建间隔中所有时间瞬间的列表。

      对服务时间进行排序。对于第一个问题,对您关心的日期进行 BinarySearch,并检查前面的条目是系统脱机维护还是重新投入使用。对于 % 正常运行时间,将(停机维护,服务恢复)成对计算,使用减法计算维护持续时间,然后将它们相加。然后用减法求总区间的长度。

      如果您的问题实际上并不意味着您正在跟踪维护间隔(或等效的使用间隔),那么您可以忽略此答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-15
        • 2011-03-13
        • 2014-01-02
        • 2012-03-10
        • 2011-03-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多