web-dev-qa-db-fra.com

Pourquoi Java.util.Set n'a-t-il pas get (int index)?

Je suis sûr qu'il y a une bonne raison, mais quelqu'un pourrait-il expliquer pourquoi l'interface Java.util.Set manque de get(int Index) ou d'une méthode similaire get()?

Il semble que les décors sont parfaits pour insérer des objets, mais je ne trouve pas un moyen élégant d’en récupérer un seul.

Si je sais que je veux le premier élément, je peux utiliser set.iterator().next(), mais sinon, il me semble que je dois transtyper vers un tableau pour récupérer un élément à un index spécifique?

Quels sont les moyens appropriés pour récupérer les données d'un ensemble? (autre que d'utiliser un itérateur)

Je suis sûr que le fait qu'elle soit exclue de l'API signifie qu'il y a une bonne raison pour ne pas le faire. Quelqu'un pourrait-il m'éclairer?

EDIT: Quelques très bonnes réponses ici, et quelques-unes en disant "plus de contexte". Le scénario spécifique était un test dbUnit, dans lequel je pouvais raisonnablement affirmer que l'ensemble renvoyé à partir d'une requête ne contenait qu'un seul élément et que j'essayais d'accéder à cet élément.

Cependant, la question est plus valable sans le scénario, car il reste plus ciblé:

Quelle est la différence entre set et list.

Merci à tous pour les réponses fantastiques ci-dessous.

226
Marty Pitt

Parce que les ensembles n'ont pas de commande. Certaines implémentations le font (en particulier celles implémentant l'interface Java.util.SortedSet), mais ce n'est pas une propriété générale des ensembles.

Si vous essayez d'utiliser des ensembles de cette façon, vous devriez plutôt utiliser une liste.

170
Michael Myers

En réalité, il s'agit d'une question récurrente lors de la rédaction d'applications JavaEE utilisant le mappage relationnel-objet (par exemple avec Hibernate); et parmi toutes les personnes qui ont répondu ici, Andreas Petersson est le seul à avoir compris le vrai problème et à y apporter la réponse correcte: il manque une liste unique à Java! (ou vous pouvez aussi l'appeler OrderedSet ou IndexedSet).

Maxwing a mentionné ce cas d'utilisation (dans lequel vous avez besoin de données commandées ET uniques) et a suggéré le SortedSet, mais ce n'est pas ce dont Marty Pitt avait réellement besoin.

Cet "IndexedSet" n'est PAS identique à un SortedSet - dans un SortedSet, les éléments sont triés à l'aide d'un comparateur (ou à l'aide de leur ordre "naturel").

Mais au lieu de cela, il est plus proche d’un LinkedHashSet (que d’autres ont également suggéré), ou plus encore d’un "ArrayListSet" (également inexistant), car il garantit que les éléments sont renvoyés dans le même ordre qu’ils ont été insérés.

Mais le LinkedHashSet est une implémentation, pas une interface! Ce qu'il faut, c'est une interface IndexedSet (ou ListSet, ou OrderedSet ou UniqueList)! Cela permettra au programmeur de spécifier qu'il a besoin d'une collection d'éléments qui ont un ordre spécifique et sans doublons, puis de l'instancier avec n'importe quelle implémentation (par exemple une implémentation fournie par Hibernate).

JDK étant open-source, cette interface sera peut-être finalement incluse dans Java 7 ...

73
Sorin Postelnicu

Ajoutez simplement un point qui n’a pas été mentionné dans la réponse de mmyers .

Si je sais que je veux le premier article, je peux utilisez set.iterator (). next (), mais sinon, il me semble que j’ai besoin de jetter un tableau pour récupérer un élément à un index spécifique?

Quels sont les moyens appropriés de récupérer des données d'un ensemble? (autre que que d'utiliser un itérateur)

Vous devez également vous familiariser avec l'interface SortedSet (dont l'implémentation la plus courante est TreeSet ). 

Un SortedSet est un ensemble (c’est-à-dire que les éléments sont uniques) est maintenu dans l’ordre par le ordre naturel des éléments ou à l’aide de Comparator. Vous pouvez facilement accéder aux premier et dernier éléments à l'aide des méthodes first() et last(). Une SortedSet est pratique de temps en temps, lorsque vous devez conserver votre collection à la fois sans doublon et ordonnée d'une certaine manière.

Edit: Si vous avez besoin d'un ensemble dont les éléments sont conservés dans l'ordre d'insertion (un peu comme une liste), consultez LinkedHashSet .

28
Jonik

Cela nous amène à nous demander quand vous devriez utiliser un ensemble et quand vous devriez utiliser une liste. D'habitude, le conseil va:

  1. Si vous avez besoin de données commandées, utilisez une liste.
  2. Si vous avez besoin de données uniques, utilisez un ensemble
  3. Si vous avez besoin des deux, utilisez soit un SortedSet (pour les données classées par comparateur), soit un OrderedSet/UniqueList (pour les données classées par insertion). Malheureusement, l'API Java n'a pas encore OrderedSet/UniqueList.

Un quatrième cas qui apparaît souvent est que vous n'avez besoin ni de l'un ni de l'autre. Dans ce cas, vous voyez que certains programmeurs utilisent des listes et d'autres des ensembles. Personnellement, je trouve très dommageable de voir l'ensemble comme une liste sans ordre - parce que c'est vraiment une toute autre bête. À moins que vous n'ayez besoin de choses comme définir l'unicité ou l'égalité, privilégiez toujours les listes.

24
waxwing

Je ne suis pas sûr que quelqu'un l'ait expliqué exactement de cette façon, mais vous devez comprendre ce qui suit:

Il n'y a pas de "premier" élément dans un ensemble.

Parce que, comme d'autres l'ont dit, les décors ne sont pas ordonnés. Un ensemble est un concept mathématique qui n'inclut pas spécifiquement la commande.

Bien sûr, votre ordinateur ne peut pas vraiment garder une liste de choses qui ne sont pas ordonnées en mémoire. Il doit y avoir des commandes. En interne, c'est un tableau ou une liste chaînée ou quelque chose. Mais vous ne savez pas vraiment ce que c'est et il n'y a pas vraiment de premier élément; l'élément qui «sort» le premier sort de cette façon par hasard, et pourrait ne pas être le premier la prochaine fois. Même si vous avez pris des mesures pour "garantir" un premier élément en particulier, il sortira toujours par hasard, car il vous est arrivé de le faire correctement pour une implémentation particulière d'un ensemble; une mise en œuvre différente pourrait ne pas fonctionner de cette façon avec ce que vous avez fait. Et, en fait, vous risquez de ne pas connaître l'implémentation que vous utilisez aussi bien que vous le pensez.

Les gens courent dans ce TOUT. LA. TEMPS. avec les systèmes de SGBDR et je ne comprends pas. Une requête SGBDR renvoie un ensemble d'enregistrements. Il s’agit du même type d’ensemble mathématique: une collection d’articles non ordonnés, mais dans ce cas les articles sont des enregistrements. Un résultat de requête SGBDR n'a aucun ordre garanti sauf si vous utilisez la clause ORDER BY, mais tout le temps que les gens le supposent, puis se déclenchent un jour où la forme de leurs données ou de leur code change légèrement et déclenche le fonctionnement de l'optimiseur de requête d’une manière différente et, tout à coup, les résultats ne sont pas affichés dans l’ordre auquel ils s’attendent. Il s’agit généralement des personnes qui n’ont pas prêté attention à la classe de base de données (ou à la lecture de la documentation ou des didacticiels) lorsqu’on leur a expliqué, dès le départ, que les résultats de la requête n’ont pas une garantie de classement.

17
skiphoppy

certaines structures de données sont absentes des collections Java standard. 

Sac (comme ensemble mais pouvant contenir des éléments plusieurs fois)

UniqueList (liste ordonnée, ne peut contenir chaque élément qu'une seule fois)

semble que vous auriez besoin d'une liste unique dans ce cas

si vous avez besoin de structures de données flexibles, cela pourrait vous intéresser Google Collections

10
Andreas Petersson

Si vous allez effectuer de nombreux accès aléatoires par index dans un ensemble, vous pouvez obtenir un tableau de ses éléments:

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

Il y a cependant deux inconvénients principaux:

  1. Ce n'est pas efficace en mémoire, car un tableau pour l'ensemble doit être créé.
  2. Si l'ensemble est modifié, la vue devient obsolète.
7
fortran

C'est vrai, les éléments de l'ensemble ne sont pas ordonnés, par définition de la collection de l'ensemble. Donc, ils ne peuvent pas être accessibles par un index.

Mais pourquoi n’avons-nous pas une méthode get (objet), non pas en fournissant l’index en tant que paramètre, mais un objet égal à celui que nous recherchons? De cette manière, nous pouvons accéder aux données de l'élément à l'intérieur du Set, simplement en connaissant ses attributs utilisés par la méthode equal.

7
walls

La seule raison pour laquelle je peux penser à utiliser un index numérique dans un ensemble serait pour itération. Pour cela, utilisez 

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

En effet, Set ne garantit que l'unicité, mais ne dit rien sur l'accès optimal ou les modèles d'utilisation. En d'autres termes, un ensemble peut être une liste ou une carte, chacune ayant des caractéristiques d'extraction très différentes.

5
jsight

J'ai rencontré des situations où je voulais réellement un Sorted Set avec un accès via index (je suis d'accord avec d'autres affiches pour qui l'accès à un Set non trié avec un index n'a aucun sens). Un exemple serait un arbre où je voulais que les enfants soient triés et que les enfants en double ne soient pas autorisés. 

J'avais besoin de l'accès via index pour les afficher et les attributs de l'ensemble s'avéraient pratiques pour éliminer efficacement les doublons.

Ne trouvant aucune collection appropriée dans les collections Java.util ou Google, j'ai trouvé facile de la mettre en œuvre moi-même. L'idée de base est d'encapsuler un SortedSet et de créer une liste lorsque l'accès via index est requis (et d'oublier la liste lorsque le SortedSet est modifié). Cela ne fonctionne bien sûr que lorsque vous modifiez le SortedSet encapsulé et que vous accédez à la liste pendant la durée de vie de la collection. Sinon, il se comporte comme une liste qui est souvent triée, c'est-à-dire trop lente.

Avec un grand nombre d’enfants, cela a beaucoup amélioré les performances par rapport à une liste triée via Collections.sort.

3
buchweizen

Veuillez noter que seules 2 structures de données de base sont accessibles via index.

  • La structure de données Array est accessible via un index avec la complexité temporelle de O(1) afin de réaliser l'opération get(int index).
  • La structure de données LinkedList est également accessible via index, mais avec O(n) complexité du temps pour réaliser l'opération get(int index).

En Java, ArrayList est implémenté à l'aide de la structure de données Array.

Alors que la structure de données Set peut généralement être implémentée via la structure de données HashTable/HashMap ou BalancedTree, elle permet de détecter rapidement l’existence d’un élément et d’ajouter un élément inexistant, généralement un Set bien implémenté peut atteindre O(1) complexité du temps contains opération. HashSet est l’implémentation la plus utilisée de Set, elle est implémentée en appelant l’API HashMap et HashMap à l’aide de chaînage séparé avec des listes chaînées (une combinaison de Array et LinkedList).

Puisque Set peut être implémenté via une structure de données différente, il n’existe pas de méthode get(int index).

2
coderz

La raison pour laquelle Set interface ne dispose pas d'un appel get de type index ou même de quelque chose de plus fondamental, tel que first () ou last (), est une opération ambiguë et donc potentiellement dangereuse opération. Si une méthode retourne un Set et que vous appelez la méthode say first () dessus, quel est le résultat attendu, étant donné que le Set générique ne donne aucune garantie sur la commande? L’objet résultant peut très bien varier d’un appel à l’autre de la méthode ou ne pas vous semer dans un faux sentiment de sécurité, jusqu’à ce que la bibliothèque que vous utilisez modifie l’implémentation en dessous et que vous constatiez maintenant que tout votre code se casse. sans raison particulière.

Les suggestions concernant les solutions de contournement répertoriées ici sont bonnes. Si vous avez besoin d'un accès indexé, utilisez une liste. Soyez prudent lorsque vous utilisez des itérateurs ou toArray avec un Set générique, car a) il n'y a aucune garantie sur la commande et b) il n'y a aucune garantie que la commande ne changera pas avec les invocations suivantes ou avec des implémentations différentes. Si vous avez besoin de quelque chose entre les deux, un SortedSet ou un LinkedHashSet est ce que vous voulez.

//Je souhaite cependant que l'interface Set ait un élément get-random-element. 

1
Dan

Java.util.Set est une collection d'articles non commandés. Cela n'a aucun sens si l'ensemble a un get (index int), car L'ensemble n'a pas d'index et vous pouvez uniquement deviner la valeur. 

Si vous le souhaitez vraiment, codez une méthode pour extraire un élément aléatoire de Set.

1
pippi longstocking

Si le jeu à trier ne vous dérange pas, vous pouvez être intéressé par le projet indexed-tree-map

Le TreeSet/ TreeMap amélioré permet d'accéder aux éléments par index ou en obtenant l'index d'un élément. Et l'implémentation est basée sur la mise à jour des poids de nœud dans l'arborescence RB. Donc, pas d'itération ou de sauvegarde par une liste ici.

0
Vitaly Sazanovich

Essayez ce code comme une alternative pour accéder aux index

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

Cela va imprimer 100.

0
Prithvi Venu

Vous pouvez faire new ArrayList<T>(set).get(index)

0
Janus Troelsen