web-dev-qa-db-fra.com

Comment obtenir le premier élément d'un Java.util.Set?

J'ai une instance Set:

Set<String> siteIdSet = (Set<String>) pContext.getParent().getPropertyValue(getCatalogProperties().getSitesPropertyName());

La pContext.getParent().getPropertyValue() est un code prêt à l'emploi sur lequel je n'ai aucun contrôle à modifier.

Exigence:

Je voulais obtenir le premier élément par défaut (toujours). Cependant, je n'ai pas trouvé de méthode get(index) comme dans un ArrayList.

Par conséquent, en ce moment, je fais comme ça.

for (Iterator<String> it = siteIdSet.iterator(); it.hasNext();) {
    siteId = it.next();
    break;
}

Y at-il un (autre) moyen efficace (bref et meilleur) pour y parvenir?

44
KrishPrabakar

De la documentation Oracle :

Comme son nom l'indique, cette interface modélise l'abstraction mathématique définie .

Dans Théorie des ensembles , "un" ensemble "est une collection d'objets distincts, considérés comme un objet à part entière". - [Wikipedia - Set] .

Mathématiquement, les éléments des ensembles ne sont pas individualisés. Leur seule identité découle de leur présence dans le décor. Par conséquent, il ne sert à rien d’obtenir le "premier" élément dans un ensemble, car conceptuellement, une telle tâche est illogique.

Il ne sert à rien d'obtenir le "premier" élément d'un ensemble, mais si tout ce dont vous avez besoin est d'obtenir un seul objet d'un ensemble (sans aucune garantie quant à l'objet concerné), vous pouvez procéder comme suit:

for(String aSiteId: siteIdSet) {
    siteId = aSiteId;
    break;
}

Ceci est un moyen légèrement plus court (que la méthode que vous avez publiée) d’obtenir le "premier" objet d’un Set. Toutefois, étant donné qu’un itérateur est toujours en cours de création (sous le capot), il n’apporte aucun avantage en termes de performances.

27
Taylor Hx

Cela retournera le premier élément

set.iterator().next();
75
Sagar Koshti

Ou, en utilisant Java8:

Object firstElement = set.stream().findFirst().get();

Et puis vous pouvez faire des choses avec tout de suite:

set.stream().findFirst().ifPresent(<doStuffHere>);

Ou, si vous souhaitez fournir une alternative si l'élément est manquant (mon exemple renvoie une nouvelle chaîne par défaut):

set.stream().findFirst().orElse("Empty string");

Vous pouvez même lancer une exception si le premier élément est manquant:

set.stream().findFirst().orElseThrow(() -> new MyElementMissingException("Ah, blip, nothing here!"));

Bravo à Alex Vulaj pour m'avoir invité à fournir plus d'exemples au-delà de la saisie initiale du premier élément.

26
Nestor Milyaev

Set est une collection unique d'objets. Donc, il n'y a pas de notion de premier élément. Si vous voulez des éléments dans l'ordre de tri, vous pouvez utiliser TreeSet à partir duquel vous pouvez récupérer le premier élément à l'aide de TreeSet # first () .

8
hanish.kh

tl; dr

Appel TreeSet::first

Déplacez les éléments et appelez first().

new TreeSet<String>( 
    pContext.getParent().getPropertyValue( … )   // Transfer elements from your `Set` to this new `TreeSet`, an implementation of the `SortedSet` interface. 
).first()

Set N'a pas de commande

Comme d'autres l'ont dit, un Set , par définition, n'a pas d'ordre. Par conséquent, demander le "premier" élément n'a pas de sens.

Certaines implémentations de Set ont un ordre tel que l'ordre dans lequel les éléments ont été ajoutés. Cette commande non officielle peut être disponible via le Iterator . Mais cet ordre est accidentel et non garanti. Si vous avez de la chance, la mise en œuvre sauvegardant votre Set pourrait bien être un SortedSet.

CAVEAT: Si l'ordre est critique, ne comptez pas sur un tel comportement . Si la fiabilité n'est pas critique, un tel comportement non documenté peut s'avérer utile. Si vous donnez Set, vous n’avez pas d’autre solution viable, essayez donc cela pourrait être mieux que rien.

Object firstElement = mySet.iterator().next();

Pour répondre directement à la question… Non, ce n'est pas vraiment un moyen plus rapide d'obtenir le premier élément de l'itérateur tout en gérant le cas possible d'un ensemble vide. Cependant, je préférerais un test if pour isEmpty plutôt que pour la boucle for de la question.

if ( ! mySet.isEmpty() ) {
    Object firstElement = mySet.iterator().next();
)

Utilisez SortedSet

Si vous souhaitez conserver un ordre de tri dans un Set, utilisez une implémentation SortedSet . Ces mises en œuvre comprennent:

Utilisez LinkedHashSet pour l'ordre d'insertion

Si tout ce dont vous avez besoin est de mémoriser les éléments dans l'ordre dans lequel ils ont été ajoutés au Set, utilisez un LinkedHashSet .

Pour citer le doc, cette classe…

maintient une liste doublement chaînée parcourant toutes ses entrées. Cette liste liée définit l'ordre des itérations, c'est-à-dire l'ordre dans lequel les éléments ont été insérés dans l'ensemble (ordre d'insertion).

6
Basil Bourque

En tant que, vous avez mentionné pContext.getParent().getPropertyValue return Set. Vous pouvez convertir Set en List pour obtenir le premier élément. Il suffit de changer votre code comme:

 Set<String> siteIdSet = (Set<String>) pContext.getParent().getPropertyValue(..);
 List<String> siteIdList=new ArrayList<>(siteIdSet);

 String firstItem=siteIdList.get(0);
3
Masudul

Set n'applique pas la commande. Rien ne garantit que vous obtiendrez toujours le "premier" élément, même si vous utilisez un itérateur sur un HashSet comme vous l'avez fait dans la question.

Si vous avez besoin d'un ordre prévisible, vous devez utiliser l'implémentation LinkedHashSet . Lorsque vous parcourez un LinkedHashSet, vous obtenez les éléments dans l'ordre que vous avez inséré. Vous devez toujours utiliser un itérateur, car avoir une méthode get dans LinkedHashSet nécessiterait que vous utilisiez la classe concrète partout.

3
Hari Menon

Pour accéder à l'élément, vous devez obtenir un itérateur. Mais Iterator ne garantit pas dans un ordre particulier à moins que ce ne soit un cas exceptionnel. il n’est donc pas certain d’obtenir le premier élément.

2
kalakanhu

Cela marche:

Object firstElement = set.toArray()[0]; 
2
Rishi Bhardwaj

C'est une question difficile que j'ai moi-même rencontrée l'autre jour. Java.util.LinkedHashSet Maintient une liste chaînée de son contenu (addition ordonnée par défaut) mais ne fournit aucun accesseur. Les autres types de structure ne fourniront pas O(1) sur add(), remove() et contains().

Vous pouvez utiliser un LinkedHashSet et obtenir son iterator(), saisir un élément et le supprimer. Si vous ne vous souciez pas trop de la vitesse ou de la mémoire lorsque vous le faites fréquemment dans de nombreux ensembles différents, c'est probablement votre solution ... mais cela m'a semblé inutile. De plus, j'ai eu un peu plus de fonctionnalités souhaitées.

J'ai fini par écrire ma propre classe, baptisée RandomAccessLinkedHashSet, qui gère simultanément une table de hachage, une liste doublement chaînée et un tableau non pertinent à l'ordre. Je l'ai écrit pour qu'il soit conforme à la fois à Set et à Deque, bien que l'implémentation de Deque soit un peu sommaire, car elle échouera à Push() qu'elle contient déjà, un peu de un tronçon pour le contrat de l'interface. Le maintien de la troisième structure, le tableau, n’est pas du tout nécessaire pour ce que vous faites, mais il permet également d’accéder à un élément aléatoire de l’ensemble. quelle que soit votre capacité, vous pouvez réellement fournir une valeur aléatoire.

Si vous êtes intéressé, je peux fournir cette source. Je ne l'ai pas encore Serialized mais cela fonctionne très bien en runtime.

Si vous ne pouvez pas garantir le type de Set fourni de quelque manière que ce soit, vous devrez vous en tenir à la chose Iterator.

2
Mumbleskates

Le vecteur a quelques caractéristiques pratiques:

Vector<String> siteIdVector = new Vector<>(siteIdSet);
String first = siteIdVector.firstElement();
String last = siteIdVector.lastElement();

Mais je suis d'accord - cela peut avoir des conséquences inattendues, car il n'est pas garanti que le jeu sous-jacent soit commandé.

0
Chris Hagn

Défini par définition n'est pas ordonné.

Vous utilisez probablement une mauvaise collection.

0
Marcin Szymczak

Il est inutile de récupérer le premier élément d'un ensemble. Si vous avez ce type d'exigence, utilisez ArrayList au lieu de sets. Les ensembles n'autorisent pas les doublons. Ils contiennent des éléments distincts.

0
Nishant Lakhara