Подтвердить что ты не робот

Сохранение сортировки TreeSet как значения изменения объекта

У меня есть объект, который определяет "естественный порядок сортировки", используя Comparable < > . Они хранятся в TreeSets.

Помимо удаления и повторного добавления объекта, существует ли другой способ обновления сортировки, когда обновляются члены, которые используются для определения порядка сортировки?

4b9b3361

Ответ 1

Как отмечали другие, нет встроенного способа. Но вы всегда можете подклассифицировать этот 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() метод в объекте данных.

Ответ 2

У меня была аналогичная проблема, я нашел эту ветку и ответ tucuxi (спасибо!), на основе которой я реализовал свой собственный UpdateableTreeSet. Моя версия предоставляет средства для

  • итерации по такому набору,
  • расписание (отложенное) обновление/удаление элементов из цикла
  • не создавая временную копию набора и, наконец,
  • делать все обновления/удаления как объемную операцию после завершения цикла.

UpdateableTreeSet скрывает большую часть сложности от пользователя. В дополнение к отложенным массовым обновлениям/абзацам одноэлементное обновление/удаление, как показано tucuxi, по-прежнему доступно в классе.

Обновление 2012-08-07: класс доступен в небольшом репозитории GitHub, включая вводный README со схематическим примером кода, а также блок тесты, показывающие, как (не) использовать его более подробно.

Ответ 3

Если вам действительно нужно использовать Set, то вам не повезло, я думаю.

Я собираюсь использовать подстановочный знак, хотя, если ваша ситуация достаточно гибкая, чтобы работать с List вместо Set, вы можете использовать Collections.sort() для повторной сортировки List по требованию. Это должно быть выполнено, если порядок List не должен сильно меняться.

Ответ 4

Это помогает узнать, будут ли ваши объекты изменяться небольшими приращениями или большими. Если каждое изменение очень мало, вы бы очень хорошо поместили свои данные в список, который вы сохранили. Для этого вам нужно

  • binarySearch, чтобы найти индекс элемента
  • изменить элемент
  • в то время как элемент больше, чем его правый сосед, поменяйте его своим правым соседом
  • или если этого не произошло: в то время как элемент меньше, чем его левый сосед, замените его своим левым соседом.

Но вы должны убедиться, что никто не может изменить элемент, не пройдя "вы", чтобы сделать это.

EDIT: Также! Глазированные списки имеют определенную поддержку только для этого:

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

Ответ 5

Я искал эту проблему, когда пытался реализовать панель кинетической прокрутки, похожую на свитки для iPhone Apple. Элементы в 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 может потребоваться некоторое время для выполнения задачи runLater платформы JavaFX, поэтому индекс включен в этот класс оболочки.

Так как scrollOffset всегда изменяется в зависимости от положения прокрутки пользователя на колесе прокрутки, нам нужен способ обновления. Обычно порядок всегда один и тот же, поскольку смещение относительно позиции позиции элемента. Индекс никогда не изменяется, но смещение может быть отрицательным или положительным в зависимости от относительного расстояния элементов от текущего значения vValue или hValue объекта ScrollPane.

Чтобы обновить по требованию только при необходимости, просто следуйте указаниям вышеупомянутого ответа Tucuxi.

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

где verticalOffsets - это TreeSet<ItemOffset>. Если вы распечатываете каждый раз, когда вызывается этот фрагмент обновления, вы увидите, что он обновлен.

Ответ 6

Только встроенный способ заключается в удалении и повторном добавлении.

Ответ 7

Я не думаю, что есть готовый способ сделать это.

Вы можете использовать шаблон наблюдателя, который уведомляет деревья, когда вы меняете значение внутри элемента, затем удаляет и повторно вставляет его.

Таким образом, вы можете неявно сохранить список отсортированным, не заботясь об этом вручную. Конечно, этот подход должен будет расширить TreeSet, изменив поведение вставки (установив наблюдаемую/уведомляющую механику только что добавленную пункт)