¿Cómo mantener una lista única en Java?

104

¿Cómo crear una lista de objetos únicos / distintos (sin duplicados) en Java?

En este momento estoy usando HashMap<String, Integer>para hacer esto ya que la clave se sobrescribe y, por lo tanto, al final podemos obtener HashMap.getKeySet()cuál sería única. Pero estoy seguro de que debería haber una mejor manera de hacer esto, ya que la parte de valor se desperdicia aquí.

Albahaca Bourque
fuente

Respuestas:

164

Puede utilizar una implementación de Set :

Alguna información de JAVADoc:

Una colección que no contiene elementos duplicados . Más formalmente, los conjuntos no contienen un par de elementos e1 y e2 tales que e1.equals (e2), y como máximo un elemento nulo. Como lo implica su nombre, esta interfaz modela la abstracción de conjuntos matemáticos.

Nota: Se debe tener mucho cuidado si se utilizan objetos mutables como elementos de configuración. El comportamiento de un conjunto no se especifica si el valor de un objeto se cambia de una manera que afecta a las comparaciones iguales mientras el objeto es un elemento del conjunto. Un caso especial de esta prohibición es que no está permitido que un conjunto se contenga a sí mismo como un elemento ».

Estas son las implementaciones:

  • HashSet

    Esta clase ofrece un rendimiento de tiempo constante para las operaciones básicas (agregar, eliminar, contener y tamaño), asumiendo que la función hash dispersa los elementos correctamente entre los cubos. Iterar sobre este conjunto requiere un tiempo proporcional a la suma del tamaño de la instancia de HashSet (el número de elementos) más la "capacidad" de la instancia de HashMap de respaldo (el número de depósitos). Por lo tanto, es muy importante no establecer la capacidad inicial demasiado alta (o el factor de carga demasiado bajo) si el rendimiento de la iteración es importante.

    Al iterar un, HashSetel orden de los elementos producidos no está definido.

  • LinkedHashSet

    Implementación de tabla hash y lista vinculada de la interfaz Set, con orden de iteración predecible. Esta implementación se diferencia de HashSet en que mantiene una lista doblemente enlazada que se ejecuta en todas sus entradas. Esta lista enlazada define el orden de iteración, que es el orden en el que se insertaron los elementos en el conjunto (orden de inserción). Tenga en cuenta que el orden de inserción no se ve afectado si un elemento se vuelve a insertar en el conjunto. (Un elemento e se vuelve a insertar en un conjunto s si se invoca s.add (e) cuando s.contains (e) devolvería verdadero inmediatamente antes de la invocación).

    Entonces, la salida del código anterior ...

     Set<Integer> linkedHashSet = new LinkedHashSet<>();
     linkedHashSet.add(3);
     linkedHashSet.add(1);
     linkedHashSet.add(2);
    
     for (int i : linkedHashSet) {
         System.out.println(i);
     }
    

    ... será necesariamente

    3
    1
    2
    
  • TreeSet

    Esta implementación proporciona un costo de tiempo log (n) garantizado para las operaciones básicas (agregar, eliminar y contiene). Por defecto, los elementos devueltos en iteración están ordenados por su " orden natural ", por lo que el código anterior ...

     Set<Integer> treeSet = new TreeSet<>();
     treeSet.add(3);
     treeSet.add(1);
     treeSet.add(2);
    
     for (int i : treeSet) {
         System.out.println(i);
     }
    

    ... dará como resultado esto:

    1
    2
    3
    

    (También puede pasar una Comparatorinstancia a un TreeSetconstructor, haciendo que ordene los elementos en un orden diferente).

    Tenga en cuenta que el orden mantenido por un conjunto (ya sea que se proporcione un comparador explícito o no) debe ser coherente con iguales si se quiere implementar correctamente la interfaz de conjunto. (Consulte Comparable o Comparator para obtener una definición precisa de coherente con iguales). Esto se debe a que la interfaz Set se define en términos de la operación igual, pero una instancia de TreeSet realiza todas las comparaciones de elementos utilizando su método compareTo (o compare), por lo que dos los elementos que se consideran iguales por este método son, desde el punto de vista del conjunto, iguales. El comportamiento de un conjunto está bien definido incluso si su ordenamiento es inconsistente con iguales; simplemente no obedece el contrato general de la interfaz Set.

Franco
fuente
Ahora estoy confundido, ¿cuál debo usar? Solo necesito mantener una lista de cadenas únicas. Entonces, básicamente, incluso cuando se agrega una cadena existente, en realidad debería agregarse.
1
La elección es suya ... HashSet es universal y rápido, el conjunto de árboles está ordenado, LinkedHashset mantiene el orden de inserción ...
Frank
6
Esto no es una LISTA ... por lo tanto, no todos los métodos de interfaz LIST están disponibles.
marcolopes
2
Un conjunto no es una lista, no puedo buscar elementos por índice en un conjunto en tiempo O (1) (acceso aleatorio).
wilmol
13

Quiero aclarar algunas cosas aquí para el póster original a las que otros han aludido pero que no han dicho explícitamente. Cuando dices que quieres una lista única, esa es la definición misma de un conjunto ordenado. Algunas otras diferencias clave entre la interfaz de conjunto y la interfaz de lista son que la lista le permite especificar el índice de inserción. Entonces, la pregunta es ¿realmente necesita la interfaz de lista (es decir, para compatibilidad con una biblioteca de terceros, etc.), o puede rediseñar su software para usar la interfaz de configuración? También debe considerar lo que está haciendo con la interfaz. ¿Es importante buscar elementos por su índice? ¿Cuántos elementos esperas en tu set? Si vas a tener muchos elementos, ¿es importante realizar pedidos?

Si realmente necesita una Lista que solo tiene una restricción única, existe la clase de Apache Common Utils org.apache.commons.collections.list.SetUniqueList que le proporcionará la interfaz de Lista y la restricción única. Eso sí, esto rompe la interfaz de la lista. Sin embargo, obtendrá un mejor rendimiento si necesita buscar en la lista por índice. Si puede lidiar con la interfaz Set y tiene un conjunto de datos más pequeño, LinkedHashSet podría ser una buena opción. Solo depende del diseño y la intención de su software.

Nuevamente, existen ciertas ventajas y desventajas para cada colección. Algunas inserciones rápidas pero lecturas lentas, algunas tienen lecturas rápidas pero inserciones lentas, etc. Tiene sentido dedicar una buena cantidad de tiempo a la documentación de las colecciones para aprender completamente sobre los detalles más finos de cada clase e interfaz.

Paul Connolly
fuente
3
Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación; siempre puede comentar sus propias publicaciones y, una vez que tenga suficiente reputación , podrá comentar en cualquier publicación .
Zach Saucier
1
De hecho, proporciona una respuesta. Si solo quiere una lista que actúe como un Conjunto, use org.apache.commons.collections.list.SetUniqueList, pero como programador, debería / nosotros ser más cuidadosos que eso y pensar más en el problema. Si esto mejora mi respuesta, "¿Cómo crear una lista única en Java?" List uniqueList = new SetUniqueList () ;, así es como ....
Paul Connolly
3
Y Zach, no estoy tratando de ser un idiota, pero ¿leíste mi respuesta antes de tu comentario? ¿O simplemente no lo entiendes? Si no lo entiende, está bien, hágamelo saber y ampliaré el tema. No creo que deba tener que escribir un tratado sobre estructuras de datos para dar una respuesta amistosa a la pregunta de alguien. Tampoco me importa buscar una manera dócil de construir la reputación de mi comentario cuando sé la respuesta y nadie más la ha proporcionado.
Paul Connolly
1
Y, por cierto, no estaba criticando ni solicitando aclaraciones al autor, solo estaba diciendo que él puede A) usar rápidamente la clase que le di, o B) tomarse el tiempo para comprender realmente las diferencias entre estas clases y relacionarse ellos a sus necesidades. B obviamente lleva más tiempo, pero resultará en un mejor código a largo plazo.
Paul Connolly
8

Utilice new HashSet<String> un ejemplo:

import java.util.HashSet;
import java.util.Set;

public class MainClass {
  public static void main(String args[]) {
    String[] name1 = { "Amy", "Jose", "Jeremy", "Alice", "Patrick" };

    String[] name2 = { "Alan", "Amy", "Jeremy", "Helen", "Alexi" };

    String[] name3 = { "Adel", "Aaron", "Amy", "James", "Alice" };

    Set<String> letter = new HashSet<String>();

    for (int i = 0; i < name1.length; i++)
      letter.add(name1[i]);

    for (int j = 0; j < name2.length; j++)
      letter.add(name2[j]);

    for (int k = 0; k < name3.length; k++)
      letter.add(name3[k]);

    System.out.println(letter.size() + " letters must be sent to: " + letter);

  }
}
tim_a
fuente
2
Simplemente agregando el programa anterior -> Se deben enviar 11 cartas a: [Aaron, Alice, James, Adel, Jose, Jeremy, Amy, Alan, Patrick, Helen, Alexi]
Ammad
4

Podría usar a HashSet<String>para mantener una colección de objetos únicos. Si los Integervalores en su mapa son importantes, entonces puede usar el containsKeymétodo de mapas para probar si su clave ya está en el mapa.

Ted Hopp
fuente
3

HashSet<String>(o) cualquier Setimplementación puede hacer el trabajo por usted. Setno permita duplicados.

Aquí está javadoc para HashSet.

kosa
fuente
2

No sé qué tan eficiente es esto, sin embargo funcionó para mí en un contexto simple.

List<int> uniqueNumbers = new ArrayList<>();

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }
Zapnologica
fuente
1

Es posible que desee utilizar una de las clases de implementación de java.util.Set<E>Interfaz, por ejemplo java.util.HashSet<String> , la clase de colección.

Una colección que no contiene elementos duplicados. Más formalmente, los conjuntos no contienen un par de elementos e1 y e2 tales que e1.equals (e2), y como máximo un elemento nulo. Como lo implica su nombre, esta interfaz modela la abstracción de conjuntos matemáticos.

Yogendra Singh
fuente