mantener la ordenación del conjunto de árboles a medida que el objeto cambia de valor


Tengo un objeto que define un 'orden natural' usando Comparable. Estos se almacenan en conjuntos de árboles.

Aparte de eliminar y volver a agregar el objeto, ¿hay otra forma de actualizar el ordenamiento cuando se actualizan los miembros que se utilizan para definir el orden de ordenación?

Author: kriegaex, 2010-04-05

7 answers

Como otros han señalado, no hay una forma incorporada. Pero siempre se puede subclase que TreeSet, con su constructor(s) de elección, y añadir la funcionalidad requerida:

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;
       }
    }
}

A partir de entonces, tendrá que llamar a ((UpdateableTreeSet)mySet).update(anElement, aValue) para actualizar el valor de ordenación y la ordenación en sí. Esto requiere que implemente un método adicional update() en su objeto de datos.

 14
Author: tucuxi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-05 23:01:01

Tuve un problema similar, encontré este hilo y la respuesta de tucuxi (¡gracias!) basado en el cual implementé mi propio UpdateableTreeSet. Mi versión proporciona medios para

  • iterar sobre tal conjunto,
  • programar actualizaciones/eliminaciones de elementos (diferidos) desde dentro del bucle
  • sin tener que crear una copia temporal del conjunto y finalmente
  • haga todas las actualizaciones/eliminaciones como una operación masiva después de que el bucle haya terminado.

UpdateableTreeSet oculta gran parte de la complejidad del usuario. Además de las actualizaciones/eliminaciones masivas diferidas, la actualización/eliminación de un solo elemento como se muestra en tucuxi sigue estando disponible en la clase.

Actualización 2012-08-07: La clase está disponible en un pequeño repositorio GitHub que incluye un README introductorio con código de ejemplo esquemático, así como pruebas unitarias que muestran cómo (no) usarlo con más detalle.

 5
Author: kriegaex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-07 16:52:35

Si realmente necesitas usar un Set, entonces no tienes suerte, creo.

Voy a agregar un comodín, sin embargo, si su situación es lo suficientemente flexible como para trabajar con un List en lugar de un Set, entonces puede usar Collections.sort() para reorganizar el List bajo demanda. Esto debería ser eficaz, si el orden List no tiene que ser cambiado mucho.

 3
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-05 17:21:31

Es útil saber si sus objetos cambiarán por pequeños incrementos o grandes. Si cada cambio es muy pequeño, haría muy bien en poner sus datos en una Lista que mantenga ordenada. Para hacer esto, usted tiene que

  1. binarySearch para encontrar el índice del elemento
  2. modificar el elemento
  3. mientras que el elemento es mayor que su vecino derecho, intercambiarlo con su vecino derecho
  4. o si eso no sucedió: mientras que el elemento es menor que su zurdo vecino, cámbialo con su vecino izquierdo.

Pero usted tiene que asegurarse de que nadie puede cambiar el elemento sin pasar por "usted" para hacerlo.

EDITAR: También! Glazed Lists tiene cierto soporte para esto:

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

 1
Author: Kevin Bourrillion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-05 22:53:46

Busqué este problema cuando estaba tratando de implementar un panel de desplazamiento cinético similar al apple iPhone wheel scrolls. Los elementos en el TreeSet son esta clase:

/**
 * 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());
    }
}

El DoubleExpression puede tardar un momento en ser enlazado en una tarea runLater de la plataforma JavaFX, esta es la razón por la que el índice se incluye en esta clase wrapper.

Dado que el scrollOffset siempre está cambiando en función de la posición de desplazamiento del usuario en la rueda de desplazamiento, necesitamos una forma de actualizar. Generalmente el orden es siempre el mismo, ya que el el desplazamiento es relativo a la posición del índice del elemento. El índice nunca cambia, pero el desplazamiento puede ser negativo o positivo dependiendo de la distancia relativa de los elementos de la propiedad actual vValue o hValue de ScrollPane.

Para actualizar bajo demanda solo cuando sea necesario, simplemente siga las instrucciones de la respuesta anterior de Tucuxi.

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

Donde verticalOffsets es un TreeSet<ItemOffset>. Si usted hace una impresión de la establecer cada vez que se llame a este fragmento de actualización, verá que es actualizar.

 1
Author: ghostNet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-23 15:07:27

Solo construido en forma es para eliminar y volver a añadir.

 0
Author: Robby Pond,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-05 17:05:12

No creo que haya una manera fuera de la caja de hacerlo.

Puede usar un patrón de observador que notifica al conjunto de árboles cada vez que cambia un valor dentro de un elemento, luego lo elimina y lo vuelve a insertar.

De esta manera puede mantener implícitamente la lista ordenada sin preocuparse de hacerlo a mano.. por supuesto, este enfoque tendrá que extender TreeSet modificando el comportamiento de inserción (estableciendo la mecánica observada/notify en el elemento recién agregado)

 -1
Author: Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-05 18:29:58