Pergunta

Eu tenho um objeto que define um 'natural ordem de classificação' usando Comparáveis<>.Estes estão sendo armazenados em TreeSets.

Diferente de remover e adicionar novamente o objeto, há outra maneira de atualizar a classificação quando os membros são usados para definir a ordem de classificação estão atualizados?

Foi útil?

Solução

Como outros já apontaram, não há integrado de forma.Mas você sempre pode subclasse que TreeSet, com o seu construtor(s) de escolha, e adicionar a funcionalidade necessária:

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 então, você terá que chamar ((UpdateableTreeSet)mySet).update(anElement, aValue) para atualizar a classificação de valor e a classificação em si.Isso exige a implementação de um adicional update() método no objeto de dados.

Outras dicas

Eu tive um problema semelhante, encontrei esta thread e tucuxi resposta (obrigado!) com base no que eu desenvolvi a minha própria UpdateableTreeSet.A minha versão fornece meios para

  • iterar através de um conjunto,
  • agendar (diferido) elemento atualizações e remoções de dentro do ciclo
  • sem ter para criar uma cópia temporária do conjunto e, finalmente,
  • fazer todas as atualizações e remoções como uma operação em massa, após um ciclo terminou.

UpdateableTreeSet esconde um monte de complexidade para o usuário.Além diferidos atualizações em massa/remoções, único elemento de atualização/remoção, como mostrado por tucuxi ainda permanece disponível na classe.

Atualização 2012-08-07:A classe está disponível em um pouco de Repositório no GitHub incluindo uma introdução leia-me com os esquemas exemplo de código, bem como testes de unidade, mostrando como (não) para usá-lo em mais detalhes.

Se você realmente precisa usar um Set, e , em seguida, você está fora de sorte, eu acho.

Eu vou jogar em um curinga, no entanto, se a sua situação é flexível o suficiente para trabalhar com um List em vez de um Set, e , em seguida, você pode usar Collections.sort() para re-ordenar a List na demanda.Esta deve ser a performance, se o List a ordem não tem que ser mudado muito.

Ele ajuda a saber se os objetos vão mudar por incrementos pequenos ou grandes.Se cada alteração é muito pequena, você faria muito bem para colocar os dados em uma Lista que você mantenha classificados.Para fazer isso, você tem que

  1. binarySearch para encontrar o índice do elemento
  2. modificar o elemento
  3. enquanto o elemento é maior do que o seu direito vizinho, trocá-lo com o seu direito vizinho
  4. ou, se isso não acontecer:enquanto o elemento é menor do que o seu vizinho esquerdo, troque-a com a sua mão esquerda vizinho.

Mas você tem que se certificar de que ninguém pode mudar o elemento, sem passar por "você" para fazê-lo.

EDITAR: Também!Vidro Listas tem algum suporte para apenas este:

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

Eu olhei para este problema, quando eu estava tentando implementar uma cinética de deslocamento do painel semelhante ao apple iPhone roda rola.Os itens no TreeSet são desta 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());
    }
}

O DoubleExpression pode demorar um momento para ser acoplado em um runLater tarefa da plataforma JavaFX, é por isso que o índice está incluído nesta classe de wrapper.

Desde o scrollOffset está sempre mudando, com base no usuário a posição de deslocamento na roda de rolagem, precisamos de um caminho para atualização.Geralmente a ordem é sempre a mesma, uma vez que o deslocamento é em relação ao item posição de índice.O índice nunca muda, mas o deslocamento pode ser negativo ou positivo, dependendo dos itens em relação à distância da atual vValue ou hValue propriedade do ScrollPane.

Para atualizar na procura somente quando necessário, simples , basta seguir a orientação da resposta acima por Tucuxi.

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

onde verticalOffsets é um TreeSet<ItemOffset>.Se você fizer uma impressão do defina cada vez que esta actualização trecho é chamado, você vai ver que ele é atualizado.

Apenas construído em forma é a de remover e adicionar novamente.

Eu não acho que há um fora-da-caixa maneira de fazê-lo.

Você pode usar um observador padrão que notifique o treeset sempre que você alterar um valor dentro de um elemento, em seguida, remove e re-insere.

Desta forma, você pode manter implicitamente a lista de classificados, sem o cuidado de fazê-lo com a mão..é claro que esta abordagem vai precisar para ampliar TreeSet modificando o comportamento de inserção (definindo a observado/notificar mecânica no recém-adicionado item)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top