6

C# 的泛型 HashSet<T> 搜索性能应该是 O(1),而 ObservableCollection<T> 的搜索性能应该是 O(n)。

我有大量独特的元素,每个元素都有一个不唯一的 DateTime 属性。

每个元素通过简单地返回其 DateTime.GetHashCode() 来计算其 HashCode。

现在我想获取我的数据的一个子集,例如日期在 2012 年 3 月到 2012 年 6 月之间的所有元素。

    var result = from p in this.Elements
                 where p.Date >= new DateTime(2012, 03, 01) &&
                       p.Date <= new DateTime(2012, 30, 06
                 select p;

如果我对 300.000 个元素的集合运行此 LINQ 查询,则返回给定范围内的 80 个元素大约需要 25 毫秒 - 我使用 HashSet<T> 还是 ObservableCollection<T> 都没有关系。

如果我手动遍历所有元素并检查它们,则需要相同的时间,约 25 毫秒。

但我确实知道给定范围内的所有日期的 HashCode。是否可以从我的 HashSet<T> 中获取具有给定 HashCodes 的所有元素?我觉得这样会快很多...

是否可以加快 LINQ 查询?我假设它没有利用我的 HashSet<T> 的特殊能力?

4

2 回答 2

5

您没有使用正确的数据结构。您应该使用排序列表(按Date属性排序)之类的东西,然后您可以在其中对范围的开头和结尾进行二进制搜索。

于 2012-05-17T16:47:30.220 回答
4

正如已经指出的那样,散列集在确定给定散列是否在集合中时非常有效。您的查询仅使用哈希集实现 IEnumerable 来迭代整个集合并进行日期比较的事实。它根本不会使用哈希。这就是手动方式与查询花费相同时间的原因。

您无法从哈希集中获取基于哈希的元素,您只能测试该元素在集合中是否存在。 如果您需要通过 has 获取字典,那么您想要的就是字典(您似乎不需要)

决定你需要对你的数据做什么,并使用一个为此优化的结构。这可能是您自己的类,它维护着多个内部结构,每个内部结构在一件事情上都很有效(比如一个用于搜索范围,另一个用于通过多个字段检查是否存在),或者可能有一个适合您需要的现有结构。但是,如果不知道你想用你的数据做什么,就很难给出建议。

要考虑的另一件事是您是否过早优化。如果手动搜索的 25 毫秒足够快,那么任何实现 IEnumerable 的结构都可能足够好。在这种情况下,您可以根据您需要的其他标准选择一个。

于 2012-05-18T09:27:34.050 回答