我正在优化Delphi应用程序的一部分,其中对象列表经常使用不同的标准进行过滤。对象保留在TObjectList
结构中,通常用每个过滤器选择整个集合的非常小的百分比(例如1%)。对象总数可以在100k范围内,并且在计算期间主要集合不会改变。虽然过滤器仅适用于少数属性,但无法对列表进行排序,以便优化所有可能的标准。
我正在寻找有关如何组织对象(数据结构)或可用于解决此问题的算法的建议。谢谢!
过滤示例:
((Object.A between 5 and 15) AND
(Object.B < 20) AND
(Object.C(AParam) > 0)) OR
(Object.IsRoot(...))
答案 0 :(得分:4)
您可以使用该字段使用排序列表,该字段最多限制您的搜索/过滤,然后执行binary search以获取此条件的索引/索引。
参考上面的示例:生成A
- 排序列表,搜索5
和15
的索引,这样您就会得到一个(更多)更小的列表(所有两者之间的索引),您必须检查其他字段(B
,C
和IsRoot
)。
Delphi(2009+)实施排序列表:DeHL.Collections.SortedList
答案 1 :(得分:3)
我知道你不使用tiOPF,但是从这个项目的源代码中可以学到很多东西。既然你可能会循环遍历过滤的对象,为什么不创建一个过滤器迭代器呢?
这个单位是一个好的开始,但我认为下载完整的资源并浏览文件更容易:http://tiopf.svn.sourceforge.net/viewvc/tiopf/tiOPF2/Trunk/Core/tiFilteredObjectList.pas?revision=1469&view=markup
此解决方案可能使用了大量RTTI:只需创建一个包含过滤器(属性名称和值)的列表,然后循环遍历这些对象。它将为您提供最大的灵活性,但代价是速度。如果您需要速度,我认为Ulrichb提供的解决方案会更好。
答案 2 :(得分:2)
在分析器中运行您的代码。找出是否有任何慢点。
通过将对象按顺序存储在内存中,您可以利用缓存效果。 (我假设你从头到尾按顺序走你的名单。)
一种方法可能是使用记录数组而不是对象列表。如果在你的情况下这是可能的。请记住,Delphi 2006中的记录可以有方法(但不是虚拟方法)。
另一个想法可能是编写自己的类分配器。我从来没有尝试过,but here's an article I found.也许尝试使用指针而不是使用TObjectList来处理对象。
答案 3 :(得分:1)
如果对象的数量很少,搜索的效率可能无关紧要,但如果经常进行缓存结果可能会有所帮助。
如果对象的数量很大,我会考虑使用内存数据库并使用SQL来进行查询。然后,数据库可以使用索引尽可能快地查找内容,并将负担转移到经过验证的工具上。我个人使用DBISAM或ElevateDB,但其他人也会使用内存数据库。通过使用真正的数据库工具,您可以轻松地将数据移动到磁盘上。
答案 4 :(得分:1)
如果要过滤的属性数量很少并且可以对它们进行排序,为什么不能有多个列表,每个列表是否按其他属性排序?每个列表为每个对象花费4个字节作为参考,加上列表本身的小开销。当然,所有这些都取决于是否可以满足内存要求。如果你正在处理很多对象,2 GB就没那么多了......
答案 5 :(得分:1)
以一般方式解决这是一个非常非常非常困难的问题。有一种软件可以整天执行此操作,它被称为 SQL查询优化器:每个现代SQL引擎中存在的一些代码将会查看您想要的内容(查询),然后看一下可用于数据的索引,可用索引的选择性,并且必须找出使用所有这些索引来为您提供结果集的最佳方法。只是为了证明问题非常困难,SQL查询优化器有时会失败并产生明显低效的计划。
我很确定你不想实现一个成熟的查询优化器,所以这里有一些关于如何让你的查询足够快的提示:
(1)选择查询中经常使用的一些字段并在其上设置索引。这些字段需要提供良好的选择性:不要对“布尔”值进行索引,当你可能同样快速(或更快)地查看整个列表时,你只需要花费时间遍历复杂的二进制搜索结构!
(2)对于每个给定的查询,选择 ONE 单个索引来预先过滤数据并逐个应用所有其他过滤器(不进行优化)。
在您的示例中:在“A”和“B”字段上创建索引。 “C”似乎是一个功能,所以不可能索引。 “IsRoot”似乎返回一个布尔值,这不值得索引。
用于数据的数据结构完全取决于您的数据。如果性能至关重要,请执行几个并进行测试。如果它只是你最喜欢的列表排序算法并不重要,那就完成了!