manter TreeSet classificar como objeto de mudança de valor
-
24-09-2019 - |
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?
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
- binarySearch para encontrar o índice do elemento
- modificar o elemento
- enquanto o elemento é maior do que o seu direito vizinho, trocá-lo com o seu direito vizinho
- 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:
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)