2

我有一个 Java ObservableList,其中包含数千个条目,每秒接收数百个更新,支持 JavaFX TableView

ObservableList由 ArrayList 支持。可以对列表应用任意排序顺序。更新可能会更改列表中单个实体的排序顺序。如果我尝试在每次更新后进行排序,我会遇到性能问题,所以目前我有一个每秒执行一次排序的后台任务。但是,如果可能的话,我想尝试实时排序。

假设列表已经排序并且我知道要更改的元素的索引,有没有比再次在列表上调用排序更有效的方法来更新元素的索引?

我已经确定我可以使用它Collections.binarySearch()来有效地找到要更新的元素的索引。还有一种方法可以有效地找到更新元素需要移动到的索引并移动 ArrayList 以使其保持有序?

我还需要处理添加和删除操作,但这些操作并不常见。

4

6 回答 6

4

我会使用 TreeSet。它可以更新具有时间复杂度的顺序,而 ArrayList 将对每个条目O(log N)进行插入排序。O(n)

于 2013-09-25T19:05:28.367 回答
4

在处理 JavaFX ObservableList / TableView组合上的排序时的一些建议:

  1. 确保您的模型类包含属性访问器。

    由于 JavaFX 2.2 实现中的一个奇怪的怪癖在 JavaFX 8+ 中不存在,因此 TableView 在处理没有属性访问器的大型数据模型时的效率远低于处理包含属性访问器函数的模型时的效率。有关更多详细信息,请参阅JavaFx tableview sort is really slow how to raise sort speed as in java swing

  2. 对 ObservableList 执行批量更改。

    每次修改被观察的 ObservableList 时,列表上的列表更改侦听器都会被触发,以将更改的排列传达给观察者。通过减少您对列表所做的修改次数,您可以减少发生的更改事件的数量,从而减少观察者通知和处理的开销。

    一个示例技术可能是将列表数据的镜像副本保存在标准的不可观察列表中,对该数据进行排序,然后在单个操作中将该排序数据设置到可观察列表中。

    为了避免过早的优化问题,只有在操作最初很慢并且优化本身提供了显着的可衡量的改进时才进行这种优化。

  3. 不要过于频繁地更新 ObservableList。

    默认情况下,JavaFX 显示帧速率的上限为 60fps。不需要多次更新可见组件(帧渲染触发器),因此请为每个脉冲批量处理所有更改。

    例如,如果您每毫秒都有一条新记录,请整理每 20 毫秒出现的所有记录并立即应用这些更改。

    为了避免过早的优化问题,只有在操作最初很慢并且优化本身提供了显着的可衡量的改进时才进行这种优化。

  4. Java 8 包含一些新的类来帮助在表格中使用已排序的内容。

    我真的不知道 Java 8 中的 TableView 排序功能和 SortList 是如何工作的。您可以通过发送电子邮件至 jfx-docs-feedback_ww@oracle.com 请求 Oracle 编写包含 Java 8 TableView 排序功能的示例和最佳实践的教程

    如需进一步参考,请参阅 javadoc:

于 2013-09-26T09:33:54.073 回答
4

关于您的回答,FXCollections.sort() 应该更快,因为它可以更好地处理 FX 属性,并且是专门为 ObservableLists 编写的。

于 2014-01-09T19:37:57.660 回答
2

不太清楚的是,您是否需要一直对列表进行排序?如果您对它进行排序只是为了更快地检索和更新您的条目,您可以使用 HashMap 更快地做到这一点。HashMap<YourClass, YourClass>如果在类中的关键字段上实现了正确的 hashCode() 和 equals() 方法,则可以创建一个。如果您只需要偶尔输出一个排序列表,也可以实现Comparable<YourClass>接口并创建一个TreeSet<YourClass>( map.keySet() ),这将创建一个排序表示,而 HashMap 中的数据保持原位。如果您需要始终对其进行排序,则可以考虑使用TreeMap<YourClass,YourClass>HashMap 来代替。Maps 比 Sets 更容易,因为它们提供了一种检索对象的方法。

于 2013-09-25T19:18:34.127 回答
1

经过一些研究,我得出结论 Collections.sort() 非常快,即使是 1 个项目。我还没有找到比更新列表中的项目并调用排序更有效的方法。我不能使用 TreeSet,因为 TableView 依赖于 List 接口,并且每次更改排序顺序时我都必须重建 TreeSet。

我发现我可以使用 Timer 或 KeyFrame 以 60 FPS 的速度进行更新,并且仍然具有合理的性能。如果不升级到 JavaFX 8,我还没有找到更好的解决方案。

于 2013-10-31T00:08:37.670 回答
0

您可以将元素从数组列表中拉出并插入(按排序顺序)更新的元素。

于 2013-09-25T19:06:08.740 回答