¿Por qué java.util.Set no tiene get (int index)?

Estoy seguro de que hay una buena razón, pero ¿podría alguien explicar por qué la interfaz java.util.Set carece de get(int Index) o de cualquier método get() similar?

Parece que los sets son geniales para poner cosas, pero no puedo encontrar una forma elegante de recuperar un solo elemento de él.

Si sé que quiero el primer artículo, puedo usar set.iterator().next() , pero de lo contrario parece que tengo que convertirlo a una matriz para recuperar un elemento en un índice específico.

¿Cuáles son las formas apropiadas de recuperar datos de un conjunto? (aparte de usar un iterador)

Estoy seguro de que el hecho de que esté excluido de la API significa que hay una buena razón para no hacer esto, ¿podría alguien por favor aclararme?

EDITAR: Algunas respuestas extremadamente buenas aquí, y algunas que dicen “más contexto”. El escenario específico era una prueba de dbUnit, donde podía afirmar razonablemente que el conjunto devuelto de una consulta tenía solo 1 elemento, y estaba tratando de acceder a ese elemento.

Sin embargo, la pregunta es más válida sin el escenario, ya que permanece más enfocada:

Cuál es la diferencia entre set y list

Gracias a todos por las fantásticas respuestas a continuación.

Porque los conjuntos no tienen orden. Algunas implementaciones sí lo hacen (particularmente las que implementan la interfaz java.util.SortedSet ), pero esa no es una propiedad general de los conjuntos.

Si intenta usar conjuntos de esta manera, debería considerar usar una lista en su lugar.

En realidad, esta es una pregunta recurrente cuando se escriben aplicaciones JavaEE que usan mapeo relacional de objetos (por ejemplo, con Hibernate); y de todas las personas que respondieron aquí, Andreas Petersson es el único que entendió el problema real y le ofreció la respuesta correcta: ¡a Java le falta una UniqueList! (o también puede llamarlo OrderedSet o IndexedSet).

Maxwing mencionó este caso de uso (en el que necesita información ordenada Y única) y sugirió SortedSet, pero esto no es lo que Marty Pitt realmente necesitaba.

Este “IndexedSet” NO es lo mismo que SortedSet – en SortedSet los elementos se ordenan usando un Comparator (o usando su orden “natural”).

Pero en cambio está más cerca de un LinkedHashSet (que otros también sugirieron), o más aún de un (también inexistente) “ArrayListSet”, porque garantiza que los elementos se devuelven en el mismo orden en que se insertaron.

¡Pero el LinkedHashSet es una implementación, no una interfaz! ¡Lo que se necesita es una interfaz IndexedSet (o ListSet, OrderedSet o UniqueList)! Esto permitirá al progtwigdor especificar que necesita una colección de elementos que tienen un orden específico y sin duplicados, y luego crear una instancia con cualquier implementación (por ejemplo, una implementación provista por Hibernate).

Como JDK es de código abierto, tal vez esta interfaz finalmente se incluya en Java 7 …

Solo agregué un punto que no fue mencionado en la respuesta de mmyers .

Si sé que quiero el primer artículo, puedo usar set.iterator (). Next (), pero de lo contrario parece que tengo que convertirlo a una matriz para recuperar un elemento en un índice específico.

¿Cuáles son las formas apropiadas de recuperar datos de un conjunto? (aparte de usar un iterador)

También debe familiarizarse con la interfaz SortedSet (cuya implementación más común es TreeSet ).

Un SortedSet es un conjunto (es decir, los elementos son únicos) que se mantiene ordenado por el orden natural de los elementos o utilizando algún Comparator . Puede acceder fácilmente a los elementos primero y último utilizando los métodos first() y last() . Un SortedSet es útil de vez en cuando, cuando necesita mantener su colección sin duplicados y ordenada de cierta manera.

Editar : si necesita un conjunto cuyos elementos se mantienen en orden de inserción (al igual que una lista), eche un vistazo a LinkedHashSet .

Esto lleva a la pregunta de cuándo debe usar un conjunto y cuándo debe usar una lista. Por lo general, el consejo dice:

  1. Si necesita datos ordenados, use una lista
  2. Si necesita datos únicos, use un conjunto
  3. Si necesita ambos, use: un SortedSet (para datos ordenados por el comparador) o un OrderedSet / UniqueList (para datos ordenados por inserción). Lamentablemente, la API de Java aún no tiene OrderedSet / UniqueList.

Un cuarto caso que aparece a menudo es que no necesita ninguno. En este caso, verá que algunos progtwigdores van con listas y algunas con conjuntos. Personalmente, me parece muy dañino verlo como una lista sin ordenar, porque en realidad es una bestia completamente diferente. A menos que necesite cosas como establecer la unicidad o establecer la igualdad, siempre favorezca las listas.

No estoy seguro si alguien lo ha explicado exactamente de esta manera, pero debe comprender lo siguiente:

No hay un “primer” elemento en un conjunto.

Porque, como han dicho otros, los conjuntos no tienen orden. Un conjunto es un concepto matemático que específicamente no incluye ordenar.

Por supuesto, su computadora no puede mantener una lista de cosas que no están ordenadas en la memoria. Tiene que tener algún orden. Internamente es una matriz o una lista vinculada o algo así. Pero realmente no sabes lo que es, y realmente no tiene un primer elemento; el elemento que sale “primero” sale de esa manera por casualidad, y puede que no sea la primera vez. Incluso si tomas medidas para “garantizar” un primer elemento en particular, todavía está saliendo por casualidad, porque acabas de hacerlo bien para una implementación particular de un Set; una implementación diferente podría no funcionar de esa manera con lo que hiciste. Y, de hecho, es posible que no sepa la implementación que está utilizando tan bien como cree que lo hace.

La gente se topa con este TODO. EL. HORA. con sistemas RDBMS y no entiendo. Una consulta RDBMS devuelve un conjunto de registros. Este es el mismo tipo de conjunto de matemáticas: una colección de elementos no ordenados, solo que en este caso los elementos son registros. Un resultado de consulta RDBMS no tiene ningún orden garantizado a menos que use la cláusula ORDER BY, pero todo el tiempo la gente asume que sí y luego se desconecta algún día cuando la forma de sus datos o código cambia ligeramente y activa el optimizador de consultas de una manera diferente y de repente los resultados no aparecen en el orden que esperan. Estas suelen ser las personas que no prestaron atención en la clase de la base de datos (o al leer la documentación o los tutoriales) cuando se les explicó, por adelantado, que los resultados de la consulta no tienen un orden garantizado.

algunas estructuras de datos faltan en las colecciones estándar de Java.

Bolsa (como conjunto pero puede contener elementos varias veces)

UniqueList (lista ordenada, puede contener cada elemento solo una vez)

parece que necesitaría una lista única en este caso

si necesita estructuras de datos flexibles, puede interesarle Google Collections

Es cierto, el elemento en Conjunto no está ordenado, por definición de la Colección de conjuntos. Entonces no pueden ser accedidos por un índice.

Pero ¿por qué no tenemos un método get (objeto), no proporcionando el índice como parámetro, sino un objeto que es igual al que estamos buscando? De esta manera, podemos acceder a los datos del elemento dentro del Conjunto, simplemente conociendo sus atributos utilizados por el método igual.

Si vas a hacer muchos accesos aleatorios por índice en un conjunto, puedes obtener una vista de matriz de sus elementos:

 Object[] arrayView = mySet.toArray(); //do whatever you need with arrayView[i] 

Sin embargo, hay dos inconvenientes principales:

  1. No es eficiente desde el punto de vista de la memoria, ya que se necesita crear una matriz para todo el conjunto.
  2. Si el conjunto se modifica, la vista se vuelve obsoleta.

Eso es porque Set solo garantiza la exclusividad, pero no dice nada sobre el acceso óptimo o los patrones de uso. Es decir, un conjunto puede ser una lista o un mapa, cada uno de los cuales tiene características de recuperación muy diferentes.

La única razón por la que puedo pensar para usar un índice numérico en un conjunto sería para la iteración. Para eso, usa

 for(A a : set) { visit(a); } 

Me encontré con situaciones en las que realmente quería un conjunto ordenado con acceso a través del índice (estoy de acuerdo con otros carteles que no tiene sentido acceder a un conjunto sin clasificar con un índice). Un ejemplo sería un árbol donde quisiera que los niños se clasifiquen y no se permiten niños duplicados.

Necesitaba el acceso a través del índice para mostrarlos y los atributos del conjunto me resultaron útiles para eliminar duplicados de manera eficiente.

Al no encontrar una colección adecuada en las colecciones java.util o google, me pareció sencillo implementarla yo mismo. La idea básica es envolver SortedSet y crear una lista cuando se requiera acceso a través del índice (y olvidar la lista cuando se cambia SortedSet). Por supuesto, esto solo funciona de manera eficiente cuando se cambia SortedSet envuelto y el acceso a la lista se separa en el tiempo de vida de la Colección. De lo contrario, se comporta como una lista que se ordena a menudo, es decir, demasiado lenta.

Con un gran número de niños, esto mejoró mucho el rendimiento en una lista que guardé por medio de Collections.sort.

Tenga en cuenta que solo se puede acceder a 2 estructuras básicas de datos a través del índice.

  • Se puede acceder a la estructura de datos de la matriz a través de un índice con O(1) complejidad de tiempo O(1) para lograr la operación get(int index) .
  • La estructura de datos LinkedList también se puede acceder a través de un índice, pero con una complejidad O(n) tiempo para lograr la operación get(int index) .

En Java, ArrayList se implementa mediante la estructura de datos Array .

Mientras que la estructura de datos de Set normalmente puede implementarse a través de la estructura de datos HashTable / HashMap o BalancedTree , para detectar rápidamente si un elemento existe y agregar un elemento no existente, normalmente un conjunto bien implementado puede lograr O(1) complejidad del tiempo contains operación. En Java, HashSet es la implementación utilizada más común de Set , se implementa llamando API de HashMap , y HashMap se implementa mediante el encadenamiento separado con listas vinculadas (una combinación de Array y LinkedList ).

Como Set se puede implementar a través de una estructura de datos diferente, no hay get(int index) método get(int index) para él.

Puede hacer una new ArrayList(set).get(index)

La razón por la cual la interfaz Set no tiene una llamada get index-type o incluso algo aún más básico, como first () o last (), es porque es una operación ambigua y, por lo tanto, una operación potencialmente peligrosa. Si un método devuelve un conjunto, y usted llama, digamos el método first (), ¿cuál es el resultado esperado, dado que el conjunto genérico no garantiza el pedido? El objeto resultante podría muy bien variar entre cada llamada del método, o podría no hacerlo y arrullarlo con una falsa sensación de seguridad, hasta que la biblioteca que está utilizando cambie la implementación debajo y ahora descubra que todo el código se rompe por ninguna razón en particular.

Las sugerencias sobre soluciones alternativas enumeradas aquí son buenas. Si necesita acceso indexado, use una lista. Tenga cuidado con el uso de iteradores o Array con un conjunto genérico, porque a) no hay garantía en el orden yb) no hay garantía de que el orden no cambie con invocaciones posteriores o con diferentes implementaciones subyacentes. Si necesita algo intermedio, SortedSet o LinkedHashSet es lo que desea.

// Sin embargo, me gustaría que la interfaz Set tuviera un elemento get-random.

java.util.Set es una colección de elementos no ordenados. No tiene ningún sentido si el conjunto tiene un índice get (int), porque Set no tiene un índice y también solo puede adivinar el valor.

Si realmente quieres esto, codifica un método para obtener un elemento aleatorio de Set.

Si no le importa que el conjunto esté ordenado, puede interesarle echar un vistazo al proyecto indexed-tree-map .

TreeSet / TreeMap mejorado proporciona acceso a elementos por índice u obtiene el índice de un elemento. Y la implementación se basa en actualizar los pesos de los nodos en el árbol RB. Así que no hay iteración o copia de seguridad por una lista aquí.

Pruebe este código como una opción alternativa para acceder a través de índices

 import java.io.*; import java.util.*; class GFG { public static void main (String[] args) { HashSet  mySet=new HashSet(); mySet.add(100); mySet.add(100); int n = mySet.size(); Integer arr[] = new Integer[n]; arr = mySet.toArray(arr); System.out.println(arr[0]); } } 

Esto imprimirá 100.

Para obtener un elemento en un conjunto, utilizo para seguir uno:

 public T getElement(Set set, T element) { T result = null; if (set instanceof TreeSet< ?>) { T floor = ((TreeSet) set).floor(element); if (floor != null && floor.equals(element)) result = floor; } else { boolean found = false; for (Iterator it = set.iterator(); !found && it.hasNext();) { if (true) { T current = it.next(); if (current.equals(element)) { result = current; found = true; } } } } return result; }