Java 在对象更改值时保持 TreeSet 排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2579679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
maintaining TreeSet sort as object changes value
提问by Stevko
I've got a object that defines a 'natural sort order' using Comparable<>. These are being stored in TreeSets.
我有一个使用 Comparable<> 定义“自然排序顺序”的对象。这些被存储在 TreeSets 中。
Other than removing and re-adding the object, is there another way to update the sort when the members that are used to define the sort order are updated?
除了删除和重新添加对象之外,当用于定义排序顺序的成员更新时,还有另一种更新排序的方法吗?
采纳答案by tucuxi
As others have noted, there is no in-built way. But you can always subclass that TreeSet, with your constructor(s) of choice, and add in the required functionality:
正如其他人所指出的,没有内置的方法。但是您始终可以使用您选择的构造函数对 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;
}
}
}
From then on, you will have to call ((UpdateableTreeSet)mySet).update(anElement, aValue)
to update the sorting value and the sorting itself. This does require you to implement an additional update()
method in your data object.
从那时起,您将不得不调用((UpdateableTreeSet)mySet).update(anElement, aValue)
以更新排序值和排序本身。这确实需要您update()
在数据对象中实现一个额外的方法。
回答by Hyman
I don't think there is a out-of-the-box way to do it.
我不认为有一种开箱即用的方法来做到这一点。
You could use an observer patternthat notifies the treeset whenever you change a value inside an element, then it removes and re-inserts it.
您可以使用观察者模式,在您更改元素内的值时通知树集,然后删除并重新插入它。
In this way you can implicitly keep the list sorted without caring of doing it by hand.. of course this approach will need to extend TreeSet
by modifying the behaviour of insertion (setting the observed/notify mechanics on the just added item)
通过这种方式,您可以隐式地保持列表排序,而无需手动进行......当然这种方法需要TreeSet
通过修改插入行为来扩展(在刚刚添加的项目上设置观察/通知机制)
回答by Robby Pond
Only built in way is to remove and re-add.
唯一的内置方式是删除和重新添加。
回答by skaffman
If you really need to use a Set
, then you're out of luck, I think.
如果你真的需要使用 a Set
,那么你就不走运了,我想。
I'm going to throw in a wildcard, though - if your situation is flexible enough to work with a List
instead of a Set
, then you can use Collections.sort()
to re-sort the List
on demand. This should be performant, if the List
order doesn't have to be changed much.
不过,我将使用通配符 - 如果您的情况足够灵活,可以使用 aList
而不是 a Set
,那么您可以使用它Collections.sort()
来List
按需重新排序。如果List
订单不必更改太多,这应该是高性能的。
回答by Kevin Bourrillion
It helps to know whether your objects will be changing by small increments or large. If each change is very small, you would do very well to put your data in a List that you keep sorted. To do this, you have to
它有助于了解您的对象是否会以小增量或大增量变化。如果每个更改都非常小,那么最好将数据放在一个列表中并保持排序。要做到这一点,你必须
- binarySearch to find the index of the element
- modify the element
- while the element is greater than its righthand neighbor, swap it with its righthand neighbor
- or if that didn't happen: while the element is less than its lefthand neighbor, swap it with its lefthand neighbor.
- binarySearch 查找元素的索引
- 修改元素
- 当元素大于其右侧邻居时,将其与其右侧邻居交换
- 或者如果没有发生:当元素小于它的左手邻居时,将它与其左手邻居交换。
But you have to make sure no one can change the element without going through "you" to do it.
但是您必须确保没有人可以在不经过“您”的情况下更改元素。
EDIT:Also! Glazed Lists has some support for just this:
编辑:还有!Glazed Lists 对此有一些支持:
回答by kriegaex
I had a similar problem, found this thread and tucuxi's answer (thanks!) based on which I implemented my own UpdateableTreeSet
. My version provides means to
我有一个类似的问题,找到了这个线程和 tucuxi 的答案(谢谢!)基于我实现了我自己的UpdateableTreeSet
. 我的版本提供了方法
- iterate over such a set,
- schedule (deferred) element updates/removals from within the loop
- without having to create a temporary copy of the set and finally
- do all the updates/removals as a bulk operation after the loop has ended.
- 迭代这样一个集合,
- 从循环内调度(延迟)元素更新/删除
- 无需创建集合的临时副本,最后
- 在循环结束后,将所有更新/删除作为批量操作进行。
UpdateableTreeSet
hides a lot of the complexity from the user. In addition to deferred bulk updates/removals, single-element update/removal as shown by tucuxi still remains available in the class.
UpdateableTreeSet
对用户隐藏了很多复杂性。除了延迟批量更新/删除之外,tucuxi 所示的单元素更新/删除在类中仍然可用。
Update 2012-08-07: The class is available in a little GitHub repositoryincluding an introductory README with schematic sample code as well as unit tests showing how (not) to use it in more detail.
2012 年 8 月 7 日更新:该类可在一个小型GitHub 存储库中获得,其中包括一个介绍性的 README,其中包含原理图示例代码以及展示如何(不)更详细地使用它的单元测试。
回答by ghostNet
I looked up this problem when I was trying to implement a kinetic scroll pane similar to the apple iPhone wheel scrolls. The items in the TreeSet
are this class:
当我尝试实现类似于苹果 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());
}
}
The DoubleExpression
may take a moment to be bound in a runLater task of the JavaFX platform, this is why the index is included in this wrapper class.
该DoubleExpression
可采取在JavaFX平台的runLater任务被束缚了一下,这就是为什么该指数包含在该包装类。
Since the scrollOffset
is always changing based on the user scroll position on the scroll wheel, we need a way to update. Usually the order is always the same, since the offset is relative to the item index position. The index never changes, but the offset could be negative or positive depending on the items relative distance from the current vValue or hValue property of the ScrollPane
.
由于scrollOffset
总是根据滚轮上的用户滚动位置而变化,因此我们需要一种更新方式。通常顺序总是相同的,因为偏移量是相对于项目索引位置的。索引永远不会改变,但偏移量可能是负数或正数,具体取决于项目与 的当前 vValue 或 hValue 属性的相对距离ScrollPane
。
To update on demand only when needed, simply follow the guidance of the above answer by Tucuxi.
只在需要时才按需更新,只需按照 Tucuxi 的上述答案的指导即可。
ItemOffset first = verticalOffsets.first();
verticalOffsets.remove(first);
verticalOffsets.add(first);
where verticalOffsetsis a TreeSet<ItemOffset>
. If you do a print out of the
set each time this update snippet is called, you will see that it is updated.
其中verticalOffsets是一个TreeSet<ItemOffset>
。如果每次调用此更新片段时都打印出该集合,您将看到它已更新。