it-swarm.com.de

Warum hat Java.util.Set nicht (int index)?

Ich bin sicher, es gibt einen guten Grund, aber könnte jemand erklären, warum die Java.util.Set-Schnittstelle get(int Index) oder eine ähnliche get()-Methode fehlt?

Es scheint, dass Sets großartig sind, um Dinge hineinzulegen, aber ich finde keine elegante Möglichkeit, ein einzelnes Objekt daraus zu finden.

Wenn ich weiß, dass ich das erste Element haben möchte, kann ich set.iterator().next() verwenden, aber anscheinend muss ich mich in ein Array umwandeln, um ein Element an einem bestimmten Index abzurufen.

Was sind die geeigneten Methoden, um Daten aus einem Set abzurufen? (anders als mit einem Iterator)

Ich bin sicher, die Tatsache, dass es von der API ausgeschlossen ist, bedeutet, dass es einen guten Grund gibt, dies nicht zu tun. Könnte mich bitte jemand aufklären?

EDIT: Einige sehr gute Antworten und einige sagen "mehr Kontext". Das spezifische Szenario war ein dbUnit-Test, bei dem ich vernünftigerweise behaupten konnte, dass der aus einer Abfrage zurückgegebene Satz nur ein Element enthielt und ich versuchte, auf dieses Element zuzugreifen.

Die Frage ist jedoch ohne das Szenario eher zutreffend, da sie fokussierter bleibt:

Was ist der Unterschied zwischen Set und Liste.

Vielen Dank an alle für die fantastischen Antworten.

226
Marty Pitt

Weil Sets keine Reihenfolge haben. Einige Implementierungen tun dies (insbesondere diejenigen, die die Java.util.SortedSet-Schnittstelle implementieren), aber dies ist keine allgemeine Eigenschaft von Mengen.

Wenn Sie Sets auf diese Weise verwenden möchten, sollten Sie stattdessen eine Liste verwenden.

170
Michael Myers

Eigentlich ist dies eine immer wiederkehrende Frage beim Schreiben von JavaEE-Anwendungen, die Object-Relational Mapping verwenden (zum Beispiel mit Hibernate). Und von all den Leuten, die hier geantwortet haben, ist Andreas Petersson der einzige, der das eigentliche Problem verstanden und die richtige Antwort darauf gegeben hat: Java fehlt eine UniqueList! (oder Sie können es auch OrderedSet oder IndexedSet nennen).

Maxwing erwähnte diesen Anwendungsfall (in dem Sie geordnete UND eindeutige Daten benötigen) und schlug das SortedSet vor. Dies ist jedoch nicht das, was Marty Pitt wirklich brauchte.

Dieses "IndexedSet" ist NICHT dasselbe wie ein SortedSet - In einem SortedSet werden die Elemente mithilfe eines Comparators (oder ihrer "natürlichen" Reihenfolge) sortiert.

Stattdessen handelt es sich eher um ein LinkedHashSet (was auch von anderen vorgeschlagen wurde) oder sogar um ein (auch inexistentes) "ArrayListSet", weil es garantiert, dass die Elemente in der Reihenfolge zurückgegeben werden, in der sie eingefügt wurden.

Das LinkedHashSet ist jedoch eine Implementierung, keine Schnittstelle! Was benötigt wird, ist eine IndexedSet- (oder ListSet- oder OrderedSet- oder UniqueList) -Schnittstelle! Dadurch kann der Programmierer angeben, dass er eine Sammlung von Elementen mit einer bestimmten Reihenfolge und ohne Duplikate benötigt, und diese dann mit einer beliebigen Implementierung (z. B. einer von Hibernate bereitgestellten Implementierung) instanziieren.

Da JDK Open Source ist, wird diese Schnittstelle möglicherweise in Java 7 enthalten sein ...

73

Fügen Sie einfach einen Punkt hinzu, der in mmyers 'Antwort nicht erwähnt wurde.

Wenn ich weiß, dass ich den ersten Artikel haben möchte, kann ich set.iterator (). next () verwenden, aber ansonsten scheint es, als müsste ich zu ein Array zum Abrufen eines Elements an einer spezifischer Index

Was sind die geeigneten Wege von Daten aus einem Satz abrufen? (andere als einen Iterator verwenden)

Sie sollten sich auch mit der SortedSet -Schnittstelle vertraut machen (deren häufigste Implementierung TreeSet ist). 

Ein SortedSet ist ein Set (d. H. Elemente sind eindeutig), das von natürliche Reihenfolge der Elemente oder mit Comparator geordnet wird. Mit den Methoden first() und last() können Sie leicht auf die ersten und letzten Elemente zugreifen. Ein SortedSet ist von Zeit zu Zeit praktisch, wenn Sie Ihre Sammlung sowohl duplikationsfrei als auch auf bestimmte Weise aufbewahren müssen.

Edit: Wenn Sie ein Set benötigen, dessen Elemente in der Reihenfolge des Einfügens gehalten werden (ähnlich einer Liste), werfen Sie einen Blick auf LinkedHashSet .

28
Jonik

Diese Art von Frage führt zu der Frage, wann Sie ein Set verwenden sollten und wann Sie eine Liste verwenden sollten. Normalerweise lautet der Rat:

  1. Wenn Sie geforderte Daten benötigen, verwenden Sie eine Liste
  2. Wenn Sie eindeutige Daten benötigen, verwenden Sie ein Set
  3. Wenn Sie beides benötigen, verwenden Sie entweder: SortedSet (für vom Komparator geordnete Daten) oder eine OrderedSet/UniqueList (für durch Einfügen geordnete Daten). Leider verfügt die Java-API noch nicht über OrderedSet/UniqueList.

Ein vierter Fall, der häufig auftaucht, ist, dass Sie keinen von beiden benötigen. In diesem Fall sehen Sie einige Programmierer mit Listen und andere mit Sets. Ich persönlich finde es sehr schädlich, eine Liste ohne Bestellung zu sehen - weil es wirklich ein ganz anderes Tier ist. Sofern Sie nicht Dinge wie Eindeutigkeit oder Gleichheit setzen müssen, bevorzugen Sie immer Listen.

24
waxwing

Ich bin nicht sicher, ob jemand es genau so formuliert hat, aber Sie müssen Folgendes verstehen:

Es gibt kein "erstes" Element in einer Menge.

Denn, wie andere gesagt haben, haben Sets keine Reihenfolge. Ein Satz ist ein mathematisches Konzept, das insbesondere keine Reihenfolge beinhaltet.

Natürlich kann Ihr Computer nicht wirklich eine Liste mit Dingen führen, die nicht im Speicher angeordnet sind. Es muss eine Bestellung geben. Intern handelt es sich um ein Array oder eine verknüpfte Liste oder etwas. Aber Sie wissen nicht wirklich, was es ist, und es hat nicht wirklich ein erstes Element. Das Element, das als "Erstes" herauskommt, kommt zufällig auf diese Weise heraus und ist beim nächsten Mal möglicherweise nicht das Erste. Selbst wenn Sie Schritte unternommen haben, um ein bestimmtes erstes Element zu "garantieren", kommt es immer noch zufällig heraus, weil Sie es gerade für eine bestimmte Implementierung eines Sets richtig gemacht haben. Eine andere Implementierung funktioniert möglicherweise nicht so, wie Sie es getan haben. Tatsächlich kennen Sie die von Ihnen verwendete Implementierung möglicherweise nicht so gut wie Sie denken.

Die Leute stoßen auf ALLE. DAS. ZEIT. mit RDBMS-Systemen und nicht verstehen. Eine RDBMS-Abfrage gibt eine Gruppe von Datensätzen zurück. Dies ist der gleiche Satz aus der Mathematik: Eine ungeordnete Sammlung von Elementen. Nur in diesem Fall handelt es sich bei den Elementen um Datensätze. Für ein RDBMS-Abfrageergebnis gibt es keine garantierte Reihenfolge, es sei denn, Sie verwenden die ORDER BY-Klausel. Wenn Sie jedoch davon ausgehen, dass dies der Fall ist, stürzen sich die Daten eines Tages ab, wenn sich die Form ihrer Daten oder ihres Codes leicht ändert und der Abfrageoptimierer zum Laufen kommt ein anderer Weg und plötzlich kommen die Ergebnisse nicht in der erwarteten Reihenfolge. Dies sind in der Regel die Personen, die in der Datenbankklasse (oder beim Lesen der Dokumentation oder Tutorials) nicht aufgepasst haben, als ihnen im Vorfeld erklärt wurde, dass die Abfrageergebnisse keine garantierte Reihenfolge haben.

17
skiphoppy

einige Datenstrukturen fehlen in den Standard-Java-Sammlungen. 

Tasche (wie Satz, kann aber Elemente mehrmals enthalten)

UniqueList (geordnete Liste, kann jedes Element nur einmal enthalten)

anscheinend benötigen Sie in diesem Fall eine eindeutige Liste

wenn Sie flexible Datenstrukturen benötigen, interessieren Sie sich möglicherweise für Google Collections

10

Wenn Sie viele zufällige Zugriffe über einen Index in einem Satz ausführen möchten, können Sie eine Array-Ansicht seiner Elemente erhalten:

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

Es gibt jedoch zwei Hauptnachteile:

  1. Es ist nicht speichereffizient, da ein Array für das gesamte Set erstellt werden muss.
  2. Wenn der Satz geändert wird, ist die Ansicht veraltet.
7
fortran

Das heißt, das Element in Set ist laut Definition der Set Collection nicht geordnet. Sie können also nicht über einen Index auf sie zugreifen.

Aber warum haben wir keine get (object) -Methode, nicht indem wir den Index als Parameter angeben, sondern ein Objekt, das dem gesuchten entspricht? Auf diese Weise können wir auf die Daten des Elements im Set zugreifen, indem wir einfach wissen, welche Attribute von der gleich-Methode verwendet werden.

7
walls

Der einzige Grund, den ich mir für die Verwendung eines numerischen Index in einem Set vorstellen kann, wäre die Iteration. Verwenden Sie dafür 

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

Dies liegt daran, dass Set nur die Eindeutigkeit garantiert, aber nichts über die optimalen Zugriffs- oder Nutzungsmuster aussagt. Ein Satz kann eine Liste oder eine Karte sein, die jeweils sehr unterschiedliche Wiederherstellungsmerkmale haben.

5
jsight

Ich bin in Situationen geraten, in denen ich eigentlich ein Sorted Set mit Zugriff per Index wollte (ich stimme mit anderen Postern überein, dass der Zugriff auf ein unsortiertes Set mit einem Index keinen Sinn macht). Ein Beispiel wäre ein Baum, in dem ich wollte, dass die Kinder sortiert werden, und doppelte Kinder waren nicht erlaubt. 

Ich brauchte den Zugriff über Index, um sie anzuzeigen, und die gesetzten Attribute waren praktisch, um Duplikate effizient zu entfernen.

Ich fand keine geeignete Sammlung in Java.util- oder Google-Sammlungen und fand es einfach, sie selbst zu implementieren. Die Grundidee besteht darin, ein SortedSet zu umschließen und eine Liste zu erstellen, wenn der Zugriff über einen Index erforderlich ist (und die Liste zu vergessen, wenn das SortedSet geändert wird). Dies funktioniert natürlich nur dann effizient, wenn das umwickelte SortedSet geändert wird und der Zugriff auf die Liste während der Lebensdauer der Collection getrennt ist. Ansonsten verhält es sich wie eine Liste, die oft sortiert wird, d. H. Zu langsam.

Bei einer großen Anzahl von Kindern verbesserte sich diese Leistung im Vergleich zu einer Liste, die ich über Collections.sort sortierte.

3
buchweizen

Bitte beachten Sie, dass nur 2 grundlegende Datenstrukturen über den Index zugänglich sind.

  • Auf die Datenstruktur Array kann über den Index mit O(1)-Zeitkomplexität zugegriffen werden, um die get(int index)-Operation zu erreichen.
  • Auf die Datenstruktur LinkedList kann auch über einen Index zugegriffen werden, jedoch mit O(n)-Zeitaufwand, um die get(int index)-Operation zu erreichen.

In Java wird ArrayList mithilfe der Datenstruktur Array implementiert.

Während die Datenstruktur Set normalerweise über die Datenstruktur HashTable/HashMap oder BalancedTree implementiert werden kann, wird zur schnellen Erkennung, ob ein Element vorhanden ist, und zum Hinzufügen nicht vorhandener Elemente normalerweise ein ordnungsgemäß implementiertes Set hinzugefügt kann eine O(1)-Zeitkomplexität contains-Operation erreichen. In Java ist HashSet die am häufigsten verwendete Implementierung von Set. Sie wird durch Aufrufen der HashMap-API implementiert. HashMap wird mit separater Verkettung mit verknüpften Listen (einer Kombination aus Array und LinkedList).

Da Set über unterschiedliche Datenstrukturen implementiert werden kann, gibt es dafür keine get(int index)-Methode.

2
coderz

Der Grund, warum Set interface keinen get-Index-Aufruf hat oder gar etwas grundlegenderes, wie first () oder last (), ist, weil es sich um eine mehrdeutige Operation handelt und daher möglicherweise gefährlich Operation. Wenn eine Methode ein Set zurückgibt und Sie beispielsweise die first () -Methode aufrufen, wie lautet das erwartete Ergebnis, da ein generisches Set keine Garantie für die Reihenfolge gibt? Das sich ergebende Objekt kann sehr wohl zwischen den einzelnen Aufrufen der Methode variieren, oder es wird Sie nicht in ein falsches Sicherheitsgefühl wiegen, bis die Bibliothek, die Sie verwenden, die Implementierung darunter ändert und Sie nun feststellen, dass der gesamte Code bricht kein bestimmter Grund.

Die hier aufgeführten Vorschläge zu Problemumgehungen sind gut. Wenn Sie einen indizierten Zugriff benötigen, verwenden Sie eine Liste. Seien Sie vorsichtig bei der Verwendung von Iteratoren oder toArray mit einem generischen Set, denn a) es gibt keine Garantie für die Bestellung und b) es gibt keine Garantie, dass sich die Bestellung bei nachfolgenden Aufrufen oder bei verschiedenen zugrunde liegenden Implementierungen nicht ändert. Wenn Sie etwas dazwischen brauchen, ist ein SortedSet oder ein LinkedHashSet das Richtige für Sie.

//Ich wünschte, die Set-Schnittstelle hätte ein get-random-Element. 

1
Dan

Java.util.Set ist eine Sammlung nicht bestellter Artikel. Es macht keinen Sinn, wenn das Set einen get (int-Index) hat, weil Set keinen Index hat und Sie auch nur den Wert erraten können. 

Wenn Sie das wirklich wollen, codieren Sie eine Methode, um ein zufälliges Element von Set zu erhalten.

1

Wenn Sie nichts dagegen haben, dass das Set sortiert wird, können Sie sich das Projekt indexed-tree-map anschauen. 

Das erweiterte TreeSet / TreeMap ermöglicht den Zugriff auf Elemente über den Index oder das Abrufen des Index eines Elements. Die Implementierung basiert auf der Aktualisierung der Knotengewichtungen im RB-Baum. Also keine Wiederholung oder Sicherung durch eine Liste hier.

0

Verwenden Sie diesen Code als alternative Option für den Zugriff über Indizes

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]);
    }
}

Dadurch werden 100 gedruckt.

0
Prithvi Venu

Sie können new ArrayList<T>(set).get(index) tun

0
Janus Troelsen