我有一个使用 Comparable<> 定义“自然排序顺序”的对象。这些存储在 TreeSets 中。
除了删除和重新添加对象之外,当用于定义排序顺序的成员更新时,是否有另一种方法来更新排序?
我有一个使用 Comparable<> 定义“自然排序顺序”的对象。这些存储在 TreeSets 中。
除了删除和重新添加对象之外,当用于定义排序顺序的成员更新时,是否有另一种方法来更新排序?
正如其他人所指出的,没有内置的方法。但是您始终可以使用您选择的构造函数对该 TreeSet 进行子类化,并添加所需的功能:
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)
来更新排序值和排序本身。这确实需要您在数据对象中实现一个附加update()
方法。
我有一个类似的问题,找到了这个线程和 tucuxi 的答案(谢谢!)基于我实现了我自己的UpdateableTreeSet
. 我的版本提供了
UpdateableTreeSet
对用户隐藏了很多复杂性。除了延迟的批量更新/删除之外,tucuxi 所示的单元素更新/删除在类中仍然可用。
2012-08-07 更新:该类在一个小的GitHub 存储库中可用,包括一个介绍性的 README,其中包含示意性示例代码以及显示如何(不)更详细地使用它的单元测试。
如果你真的需要使用 a Set
,那么你就不走运了,我想。
不过,我将使用通配符 - 如果您的情况足够灵活,可以使用 aList
而不是 a Set
,那么您可以使用按需Collections.sort()
重新排序。如果订单不需要改变太多List
,这应该是高效的。List
唯一的内置方式是删除并重新添加。
它有助于了解您的对象是否会以小增量或大增量进行更改。如果每次更改都非常小,您最好将数据放入您保持排序的列表中。为此,您必须
但是您必须确保没有人可以在不通过“您”的情况下更改元素。
编辑:还有!Glazed Lists 对此有一些支持:
当我尝试实现类似于苹果 iPhone 滚轮滚动的动态滚动窗格时,我查找了这个问题。中的项目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());
}
}
可能需要一些时间才能绑定到 JavaFX 平台的DoubleExpression
runLater 任务中,这就是索引包含在这个包装类中的原因。
由于scrollOffset
总是根据用户在滚轮上的滚动位置而变化,因此我们需要一种更新方法。通常顺序总是相同的,因为偏移量是相对于项目索引位置的。索引永远不会改变,但偏移量可能是负数或正数,具体取决于项目与当前 vValue 或 hValue 属性的相对距离ScrollPane
。
要仅在需要时按需更新,只需按照图库西上述答案的指导进行操作即可。
ItemOffset first = verticalOffsets.first();
verticalOffsets.remove(first);
verticalOffsets.add(first);
其中verticalOffsets是一个TreeSet<ItemOffset>
。如果每次调用此更新片段时都打印出集合,您将看到它已更新。
我不认为有一种开箱即用的方式来做到这一点。
您可以使用观察者模式,每当您更改元素内的值时通知树集,然后删除并重新插入它。
通过这种方式,您可以隐式地保持列表排序,而无需手动进行。当然,这种方法需要TreeSet
通过修改插入的行为来扩展(在刚刚添加的项目上设置观察/通知机制)