3

我正在优化 Delphi 应用程序的一部分,其中经常使用不同的标准过滤对象列表。对象保存在TObjectList结构中,通常使用每个过滤器选择整个集合的非常小的百分比(例如 1%)。对象的总数可以在 100k 范围内,并且在计算期间主集不会改变。尽管过滤器仅适用于少数几个属性,但无法以优化所有可能标准的方式对列表进行排序。

我正在寻找有关如何组织对象(数据结构)或可用于解决此问题的算法的建议。谢谢!

过滤器示例:

  ((Object.A between 5 and 15) AND
  (Object.B < 20) AND
  (Object.C(AParam) > 0)) OR
  (Object.IsRoot(...))
4

6 回答 6

4

您可以使用使用该字段的排序列表,它最多限制您的搜索/过滤,然后执行二进制搜索以获取此条件的索引/索引。

参考您上面的示例:生成一个A排序列表,搜索 and 的索引,5因此15您将获得一个(小得多)的列表(两者之间的所有索引),您必须在其中检查其他字段BCIsRoot) .

Delphi (2009+) 排序列表的实现:DeHL.Collections.SortedList

于 2010-02-27T15:07:11.550 回答
3

我知道你不使用 tiOPF,但是从这个项目的源代码中可以学到很多东西。既然您可能会遍历过滤的对象,为什么不创建一个过滤器迭代器呢?

这个单元是一个好的开始,但我认为下载完整的源代码并浏览文件更容易:http: //tiopf.svn.sourceforge.net/viewvc/tiopf/tiOPF2/Trunk/Core/tiFilteredObjectList.pas?修订=1469&view=标记

这个解决方案可能使用了很多 RTTI:只需创建一个带有过滤器(属性名称和值)的列表并遍历对象。它将为您提供最大的灵活性,但会牺牲一些速度。如果您需要速度,我认为 Ulrichb 提供的解决方案会更好。

于 2010-02-27T15:17:32.013 回答
2

想法#1

在分析器中运行您的代码。找出是否有任何慢点。

想法#2

可能您可以通过将对象顺序存储在内存中来利用缓存效果。(我假设您从头到尾按顺序遍历您的列表。)

一种方法可能是使用记录数组而不是对象列表。如果这在你的情况下是可能的。请记住,Delphi 2006 中的记录可以有方法(但不能有虚拟方法)。

另一个想法可能是编写自己的类分配器。我从未尝试过,但这是我找到的一篇文章。也许尝试使用指针而不是使用 TObjectList 来遍历对象。

于 2010-02-27T16:18:32.467 回答
1

如果对象的数量很少,那么搜索的效率可能并不重要,尽管如果经常缓存结果可能会有所帮助。

如果对象的数量很大,我会考虑使用内存数据库并使用 SQL 进行查询。然后,数据库可以使用索引尽可能快地查找内容,并将负担转交给经过验证的工具。我个人使用 DBISAM 或 ElevateDB,但其他人也会使用内存数据库。通过使用真正的数据库工具,如果数据变得非常大,您可以轻松地将数据移动到磁盘。

于 2010-02-27T16:45:35.913 回答
1

如果要过滤的属性数量很少并且可以排序,为什么不拥有多个列表,每个列表都由另一个属性排序?每个列表为每个对象花费 4 个字节用于引用,外加列表本身的少量开销。当然,一切都取决于能否满足内存需求。2 GB 不算多,如果您要处理很多对象...

于 2010-02-27T19:26:36.380 回答
1

这是一个非常非常难以以通用方式解决的问题。有一种软件整天都在做这件事,它被称为SQL 查询优化器:每个现代 SQL 引擎中存在的那段代码会看看你想要什么(查询),然后看看索引可用于您的数据,可用索引的选择性,它必须找出最佳方式来使用所有这些来为您提供结果集。只是为了证明这个问题非常困难,SQL 查询优化器有时会失败并产生明显低效的计划。

我很确定你不想实现一个成熟的查询优化器,所以这里有一些关于如何让你的查询足够快的提示:

(1) 选择查询中经常用到的一些字段,并在上面设置索引。这些字段需要提供良好的选择性:不要在“布尔”值上建立索引,当您可能以同样快(或更快)的速度查看整个列表时,您只会浪费时间遍历复杂的二进制搜索结构!

(2) 对于每个给定的查询,选择一个单一的索引来预过滤数据,并一一应用所有其他过滤器(没有优化)。

在您的示例中:在“A”和“B”字段上创建索引。“C”似乎是一个函数,因此无法索引。“IsRoot”似乎返回一个布尔值,不值得索引。

用于数据的数据结构完全取决于您的数据。如果性能至关重要,请实施多个并进行测试。如果它不重要,只需您最喜欢的列表排序算法即可!

于 2010-02-28T09:57:48.650 回答