Eu sei SortedSet
, mas no meu caso preciso de algo que implemente List
, e não Set
. Então, há uma implementação lá fora, na API ou em outro lugar?
Não deve ser difícil de implementar, mas imaginei por que não perguntar às pessoas aqui primeiro?
java
list
collections
duplicates
Yuval
fonte
fonte
Respostas:
Não há coleção Java na biblioteca padrão para fazer isso.
LinkedHashSet<E>
preserva a ordenação de forma semelhante a aList
, entretanto, se você envolver seu conjunto em aList
quando quiser usá-lo como a,List
obterá a semântica desejada.Alternativamente, o Commons Collections (ou
commons-collections4
, para a versão genérica) tem umList
que faz o que você já quer:SetUniqueList
/SetUniqueList<E>
.fonte
Aqui está o que eu fiz e funciona.
Supondo que eu tenha um
ArrayList
com o qual trabalhar, a primeira coisa que fiz foi criar um novoLinkedHashMap
.LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
Em seguida, tento adicionar meu novo elemento ao
LinkedHashSet
. O método add não altera oLinkedHasSet
e retorna false se o novo elemento for uma duplicata. Portanto, essa se torna uma condição que posso testar antes de adicionar aoArrayList
.if (hashSet.add(E)) arrayList.add(E);
Esta é uma maneira simples e elegante de evitar que duplicatas sejam adicionadas a uma lista de arrays. Se você quiser, pode encapsulá-lo e sobrescrever o método add em uma classe que estende o
ArrayList
. Apenas lembre-se de lidar com issoaddAll
percorrendo os elementos e chamando o método add.fonte
Então aqui está o que eu fiz eventualmente. Espero que isto ajude alguém.
class NoDuplicatesList<E> extends LinkedList<E> { @Override public boolean add(E e) { if (this.contains(e)) { return false; } else { return super.add(e); } } @Override public boolean addAll(Collection<? extends E> collection) { Collection<E> copy = new LinkedList<E>(collection); copy.removeAll(this); return super.addAll(copy); } @Override public boolean addAll(int index, Collection<? extends E> collection) { Collection<E> copy = new LinkedList<E>(collection); copy.removeAll(this); return super.addAll(index, copy); } @Override public void add(int index, E element) { if (this.contains(element)) { return; } else { super.add(index, element); } } }
fonte
Por que não encapsular um conjunto com uma lista, classificar como:
new ArrayList( new LinkedHashSet() )
Isso deixa a outra implementação para alguém que é um verdadeiro mestre em coleções ;-)
fonte
Você deve considerar seriamente a resposta de dhiller:
new ArrayList(set)
(ou anew LinkedList(set)
, qualquer coisa).Acho que a solução que você postou com o
NoDuplicatesList
tem alguns problemas, principalmente com ocontains()
método, além de sua classe não lidar com a verificação de duplicatas na coleção passada para o seuaddAll()
método.fonte
Eu precisava de algo assim, então fui às coleções comuns e usei o
SetUniqueList
, mas quando executei alguns testes de desempenho, descobri que parece não estar otimizado em comparação com o caso se eu quiser usar umSet
e obter umArray
usando oSet.toArray()
método.O
SetUniqueTest
tomou 20: 1 tempo para preencher e depois transversal 100.000 Cordas comparando à outra implementação, o que é uma grande diferença negócio.Então, se você se preocupa com o desempenho, eu recomendo que você use Set and Get an Array em vez de usar o
SetUniqueList
, a menos que você realmente precise da lógica deSetUniqueList
, então você precisará verificar outras soluções ...Método principal do código de teste :
public static void main(String[] args) { SetUniqueList pq = SetUniqueList.decorate(new ArrayList()); Set s = new TreeSet(); long t1 = 0L; long t2 = 0L; String t; t1 = System.nanoTime(); for (int i = 0; i < 200000; i++) { pq.add("a" + Math.random()); } while (!pq.isEmpty()) { t = (String) pq.remove(0); } t1 = System.nanoTime() - t1; t2 = System.nanoTime(); for (int i = 0; i < 200000; i++) { s.add("a" + Math.random()); } s.clear(); String[] d = (String[]) s.toArray(new String[0]); s.clear(); for (int i = 0; i < d.length; i++) { t = d[i]; } t2 = System.nanoTime() - t2; System.out.println((double)t1/1000/1000/1000); //seconds System.out.println((double)t2/1000/1000/1000); //seconds System.out.println(((double) t1) / t2); //comparing results
}
Atenciosamente, Mohammed Sleem
fonte
NOTA: não leva em consideração a implementação de subList .
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; public class UniqueList<T> extends ArrayList<T> { private static final long serialVersionUID = 1L; /** Unique elements SET */ private final Set<T> set=new HashSet(); /** Used by addAll methods */ private Collection<T> addUnique(Collection<? extends T> col) { Collection<T> unique=new ArrayList(); for(T e: col){ if (set.add(e)) unique.add(e); } return unique; } @Override public boolean add(T e) { return set.add(e) ? super.add(e) : false; } @Override public boolean addAll(Collection<? extends T> col) { return super.addAll(addUnique(col)); } @Override public void add(int index, T e) { if (set.add(e)) super.add(index, e); } @Override public boolean addAll(int index, Collection<? extends T> col) { return super.addAll(index, addUnique(col)); } }
fonte
A documentação para interfaces de coleção diz:
Portanto, se você não quiser duplicatas, provavelmente não deve usar uma lista.
fonte
no
add
método, por que não usarHashSet.add()
para verificar duplicatas em vez deHashSet.consist()
.HashSet.add()
retornarátrue
se não houver duplicata efalse
caso contrário.fonte
HashSet#consist()
?No topo da minha cabeça, as listas permitem duplicatas. Você pode implementar rapidamente ae
UniqueArrayList
substituir todas as funçõesadd
/insert
para verificarcontains()
antes de chamar os métodos herdados. Para uso pessoal, você só poderia implementar oadd
método que usa e substituir os outros para lançar uma exceção no caso de futuros programadores tentarem usar a lista de uma maneira diferente.fonte
Acabei de fazer minha própria UniqueList em minha pequena biblioteca como esta:
package com.bprog.collections;//my own little set of useful utilities and classes import java.util.HashSet; import java.util.ArrayList; import java.util.List; /** * * @author Jonathan */ public class UniqueList { private HashSet masterSet = new HashSet(); private ArrayList growableUniques; private Object[] returnable; public UniqueList() { growableUniques = new ArrayList(); } public UniqueList(int size) { growableUniques = new ArrayList(size); } public void add(Object thing) { if (!masterSet.contains(thing)) { masterSet.add(thing); growableUniques.add(thing); } } /** * Casts to an ArrayList of unique values * @return */ public List getList(){ return growableUniques; } public Object get(int index) { return growableUniques.get(index); } public Object[] toObjectArray() { int size = growableUniques.size(); returnable = new Object[size]; for (int i = 0; i < size; i++) { returnable[i] = growableUniques.get(i); } return returnable; } }
Eu tenho uma classe TestCollections parecida com esta:
package com.bprog.collections; import com.bprog.out.Out; /** * * @author Jonathan */ public class TestCollections { public static void main(String[] args){ UniqueList ul = new UniqueList(); ul.add("Test"); ul.add("Test"); ul.add("Not a copy"); ul.add("Test"); //should only contain two things Object[] content = ul.toObjectArray(); Out.pl("Array Content",content); } }
Funciona bem. Tudo o que ele faz é adicionar a um conjunto se ainda não o tiver e houver um Arraylist que pode ser retornado, bem como um array de objetos.
fonte