将TreeSetsorting为对象更改值

我有一个使用Comparable <>定义“自然sorting顺序”的对象。 这些被存储在TreeSets中。

除了删除和重新添加对象之外,是否还有另一种方法来更新用于定义sorting顺序的成员更新的sorting?

正如其他人所指出的,没有内build的方法。 但是,您总是可以使用您的构造函数inheritance该TreeSet的子类,并添加所需的function:

 public class UpdateableTreeSet<T extends Updateable> extends TreeSet<T> { // definition of updateable interface Updateable{ void update(Object value); } // constructors here ... // 'update' method; returns false if removal fails or duplicate after update public boolean update(T e, Object value) { if (remove(e)) { e.update(value); return add(e); } else { return false; } } } 

从此,您将不得不调用((UpdateableTreeSet)mySet).update(anElement, aValue)来更新sorting值和sorting本身。 这确实要求您在数据对象中实现一个额外的update()方法。

我有一个类似的问题,发现这个线程和tucuxi的答案(谢谢!)基于我实现我自己的UpdateableTreeSet 。 我的版本提供了手段

  • 迭代这样一个集合,
  • 从循环内调度(延迟)元素更新/删除
  • 而无需创build集合的临时副本,最后
  • 在循环结束后,将所有更新/清除作为批量操作执行。

UpdateableTreeSet隐藏了用户的很多复杂性。 除了推迟的批量更新/删除,tucuxi所示的单元素更新/删除仍然可以在课堂上使用。

更新2012年8月7日:这个类可以在一个小GitHub仓库中使用,包括一个介绍性的自述文件和示意代码示例,以及unit testing,显示如何(不)更详细地使用它。

如果你确实需要使用一个Set ,那么你的运气不好,我想。

但是,如果您的情况足够灵活,可以使用List而不是Set ,那么您可以使用Collections.sort()对需求进行重新sorting。 这应该是高性能的,如果List顺序不需要改变太多。

这有助于了解你的物体是否会以小的增量或大的变化。 如果每个更改都非常小,那么将数据放在您保持sorting的List中将会非常好。 要做到这一点,你必须

  1. binarySearch来查找元素的索引
  2. 修改元素
  3. 而元素大于右边的邻居,则将其与右边的邻居交换
  4. 或者如果没有发生:当元素小于其左手邻居时,将其与左手邻居交换。

但是你必须确保没有人能通过“你”来改变这个元素。

编辑:也! 给上釉列表有一些支持这样的:

http://publicobject.com/glazedlists/glazedlists-1.5.0/api/ca/odell/glazedlists/ObservableElementList.html

当我尝试实现类似于苹果iPhone滚轮的dynamic滚动窗格时,我查找了这个问题。 TreeSet中的项目是这个类:

 /** * Data object that contains a {@code DoubleExpression} bound to an item's * relative distance away from the current {@link ScrollPane#vvalueProperty()} or * {@link ScrollPane#hvalueProperty()}. Also contains the item index of the * scrollable content. */ private static final class ItemOffset implements Comparable<ItemOffset> { /** * Used for floor or ceiling searches into a navigable set. Used to find the * nearest {@code ItemOffset} to the current vValue or hValue of the scroll * pane using {@link NavigableSet#ceiling(Object)} or * {@link NavigableSet#floor(Object)}. */ private static final ItemOffset ZERO = new ItemOffset(new SimpleDoubleProperty(0), -1); /** * The current offset of this item from the scroll vValue or hValue. This * offset is transformed into a real pixel length of the item distance from * the current scroll position. */ private final DoubleExpression scrollOffset; /** The item index in the list of scrollable content. */ private final int index; ItemOffset(DoubleExpression offset, int index) { this.scrollOffset = offset; this.index = index; } /** {@inheritDoc} */ @Override public int compareTo(ItemOffset other) { double d1 = scrollOffset.get(); double d2 = other.scrollOffset.get(); if (d1 < d2) { return -1; } if (d1 > d2) { return 1; } // Double expression has yet to be bound // If we don't compare by index we will // have a lot of values ejected from the // navigable set since they will be equal. return Integer.compare(index, other.index); } /** {@inheritDoc} */ @Override public String toString() { return index + "=" + String.format("%#.4f", scrollOffset.get()); } } 

DoubleExpression可能需要一些时间来绑定在JavaFX平台的runLater任务中,这就是为什么索引被包含在这个包装类中。

由于scrollOffset总是根据滚轮上的用户滚动位置而变化,所以我们需要一种更新方式。 通常订单总是相同的,因为偏移是相对于物品索引位置。 索引不会改变,但偏移可能是负值或正值,取决于与ScrollPane当前vValue或hValue属性的项目相对距离。

只有在需要的时候才按需更新,只需按照上面的答案来指导。

 ItemOffset first = verticalOffsets.first(); verticalOffsets.remove(first); verticalOffsets.add(first); 

verticalOffsetsTreeSet<ItemOffset> 。 如果每次调用这个更新片段时,您都会从这个集合中进行打印,您将会看到它已经被更新。

只有内置的方法是删除和重新添加。

我不认为有一个现成的方式来做到这一点。

每当你改变一个元素内的一个值时,你可以使用一个观察者模式来通知treeset,然后移除并重新插入它。

通过这种方式,可以隐式地保持列表的sorting而不用手工去做。当然,这种方法需要通过修改插入的行为来扩展TreeSet (在刚添加的项目上设置观察/通知机制)