Lo sé SortedSet
, pero en mi caso necesito algo que implemente List
, y no Set
. Entonces, ¿existe una implementación, en la API o en otro lugar?
No debería ser difícil de implementar yo mismo, pero pensé por qué no preguntar a la gente aquí primero
java
list
collections
duplicates
Yuval
fuente
fuente
Respuestas:
No hay una colección de Java en la biblioteca estándar para hacer esto.
LinkedHashSet<E>
SinList
embargo, conserva el orden de manera similar a a , por lo que si envuelve su conjunto en aList
cuando quiera usarlo como aList
, obtendrá la semántica que desea.Alternativamente, las Colecciones Comunes (o
commons-collections4
, para la versión genérica) tiene unList
que ya hace lo que quieres:SetUniqueList
/SetUniqueList<E>
.fuente
Esto es lo que hice y funciona.
Suponiendo que tengo un
ArrayList
archivo con el que trabajar, lo primero que hice fue crear un archivoLinkedHashMap
.LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
Luego intento agregar mi nuevo elemento al
LinkedHashSet
. El método add no altera elLinkedHasSet
y devuelve falso si el nuevo elemento es un duplicado. Entonces, esto se convierte en una condición que puedo probar antes de agregar alArrayList
.if (hashSet.add(E)) arrayList.add(E);
Esta es una forma simple y elegante de evitar que se agreguen duplicados a una lista de matrices. Si lo desea, puede encapsularlo y anular el método add en una clase que amplíe el
ArrayList
. Solo recuerde lidiar conaddAll
recorrer los elementos y llamar al método add.fuente
Así que esto es lo que hice finalmente. Espero que esto ayude a alguien más.
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); } } }
fuente
¿Por qué no encapsular un conjunto con una lista, ordenar como:
new ArrayList( new LinkedHashSet() )
Esto deja la otra implementación para alguien que sea un verdadero maestro de Colecciones ;-)
fuente
Debería considerar seriamente la respuesta de dhiller:
new ArrayList(set)
(o anew LinkedList(set)
, lo que sea).Creo que la solución que publicaste con el
NoDuplicatesList
tiene algunos problemas, principalmente con elcontains()
método, además de que tu clase no controla la verificación de duplicados en la Colección pasada a tuaddAll()
método.fuente
Necesitaba algo así, así que fui a las colecciones de commons y usé el
SetUniqueList
, pero cuando ejecuté una prueba de rendimiento, descubrí que no parece optimizado en comparación con el caso si quiero usar aySet
obtener unArray
usando elSet.toArray()
método.La
SetUniqueTest
tomó 20: 1 vez para llenar y luego travesía 100.000 Cuerdas que comparan a la otra aplicación, que es una gran diferencia acuerdo.Entonces, si te preocupa el rendimiento, te recomiendo que uses Set and Get an Array en lugar de usar el
SetUniqueList
, a menos que realmente necesites la lógica delSetUniqueList
, entonces tendrás que verificar otras soluciones ...Método principal del código de prueba :
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
}
Saludos, Mohammed Sleem
fuente
NOTA: no tiene en cuenta la implementación 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)); } }
fuente
La documentación para las interfaces de colección dice:
Entonces, si no desea duplicados, probablemente no debería usar una lista.
fuente
en el
add
método, ¿por qué no usarHashSet.add()
para verificar duplicados en lugar deHashSet.consist()
.HashSet.add()
Volverátrue
si no hay duplicado y de lofalse
contrario.fuente
HashSet#consist()
?Fuera de mi cabeza, las listas permiten duplicados. Puede implementar rápidamente ay
UniqueArrayList
anular todas las funcionesadd
/insert
para verificarcontains()
antes de llamar a los métodos heredados. Para uso personal, solo puede implementar eladd
método que usa y anular los demás para lanzar una excepción en caso de que los futuros programadores intenten usar la lista de una manera diferente.fuente
Acabo de hacer mi propia UniqueList en mi propia pequeña 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; } }
Tengo una clase TestCollections que se ve así:
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 bien. Todo lo que hace es agregar a un conjunto si aún no lo tiene y hay una Arraylist que se puede devolver, así como una matriz de objetos.
fuente