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