Domanda

Ho un oggetto che definisce un 'ordinamento naturale' utilizzando Comparable <>. Questi vengono memorizzati in TreeSets.

Oltre a eliminare e aggiungere nuovamente l'oggetto, c'è un altro modo per aggiornare l'ordinamento quando gli elementi che vengono utilizzati per definire l'ordinamento vengono aggiornati?

È stato utile?

Soluzione

modo Come altri hanno notato, c'è costruito in-no. Ma si può sempre sottoclasse che TreeSet, con il costruttore (s) di scelta, e aggiungere le funzionalità richieste:

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

Da allora in poi, si dovrà chiamare ((UpdateableTreeSet)mySet).update(anElement, aValue) per aggiornare il valore di ordinamento e lo stesso ordinamento. Questo non richiede di implementare un metodo update() supplementare nel vostro oggetto di dati.

Altri suggerimenti

Ho avuto un problema simile, trovato questa discussione e la risposta di TUCUXI (grazie!), In base alla quale ho implementato il mio UpdateableTreeSet. La mia versione fornisce i mezzi per

  • iterazioni su una tale insieme,
  • pianificazione (differita) aggiornamenti elemento / rimozioni all'interno del loop
  • senza dover creare una copia temporanea del set e infine
  • fare tutti gli aggiornamenti / rimozioni come un'operazione di massa dopo il ciclo è terminato.

UpdateableTreeSet nasconde un sacco di complessità da parte dell'utente. Oltre agli aggiornamenti differite massa / rimozioni, aggiornamento singolo elemento / rimozione come dimostrano TUCUXI rimane ancora disponibile nella classe.

Aggiornamento 2012-08-07: La classe è disponibile in un po ' GitHub repository tra cui un README introduttivo con il codice di esempio schematico nonché unit test mostra come (non) di utilizzare in modo più dettagliato.

Se si ha realmente bisogno di utilizzare un Set, allora sei fuori di fortuna, penso.

ho intenzione di gettare in un jolly, anche se - se la vostra situazione è abbastanza flessibile da lavoro con un List invece di un Set, quindi è possibile utilizzare Collections.sort() per riordinare il List su richiesta. Questo dovrebbe essere performante, se l'ordine List non deve essere cambiato molto.

E 'utile sapere se i vostri oggetti cambieranno da piccoli incrementi o di grandi dimensioni. Se ogni cambiamento è molto piccolo, si farebbe molto bene a mettere i vostri dati in un elenco che si mantiene ordinati. Per fare questo, è necessario

  1. binarySearch per trovare l'indice dell'elemento
  2. modificare l'elemento
  3. mentre l'elemento è maggiore rispetto al suo vicino di destra, di swap con il suo vicino di destra
  4. o, se ciò non è accaduto:., Mentre l'elemento è inferiore al suo vicino di sinistra, scambio con il suo vicino di sinistra

Ma bisogna assicurarsi che nessuno può cambiare l'elemento senza passare attraverso "tu" a farlo.

Modifica anche! Liste vetri ha qualche supporto proprio per questo:

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

ho guardato questo problema quando stavo cercando di realizzare un pannello di scorrimento cinetica simile a rotoli ruota iPhone di Apple. Le voci nel TreeSet sono questa classe:

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

Il DoubleExpression può prendere un momento di essere vincolato in un compito runLater della piattaforma JavaFX, questo è il motivo per cui l'indice è incluso in questa classe wrapper.

Poiché il scrollOffset cambia sempre basata sulla posizione dell'utilizzatore scorrimento sulla rotellina, abbiamo bisogno di un modo di aggiornamento. Solitamente l'ordine è sempre lo stesso, poiché l'offset è relativo alla posizione di indice dell'elemento. L'indice non cambia mai, ma l'offset potrebbe essere positivo o negativo a seconda delle voci relativa distanza dalla corrente vValue o hValue proprietà del ScrollPane.

Per aggiornare su richiesta solo quando necessario , è sufficiente seguire la guida dello risposta di cui sopra da TUCUXI.

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

dove verticalOffsets è un TreeSet<ItemOffset>. Se fate una stampa della impostare ogni volta che questo aggiornamento frammento si chiama, si vedrà che è aggiornato.

Solo costruito in modo è quello di rimuovere e ri-add.

Non credo ci sia un modo out-of-the-box per farlo.

Si potrebbe utilizzare un pattern Observer che notifica l'TreeSet ogni volta che si cambia un valore all'interno di un elemento, allora rimuove e re-inserisce.

In questo modo si può implicitamente mantenere la lista ordinata, senza preoccuparsi di farlo a mano .. Naturalmente questo approccio sarà necessario estendere TreeSet modificando il comportamento di inserimento (impostazione della osservato / avvisare meccanica sulla voce appena aggiunta)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top