Ich bin mir sicher, dass es einen guten Grund gibt, aber könnte jemand bitte erklären, warum die java.util.Set
Schnittstelle fehlt get(int Index)
, oder eine ähnliche get()
Methode?
Es scheint, dass Sets großartig sind, um Dinge hinein zu bringen, aber ich kann keinen eleganten Weg finden, um einen einzelnen Gegenstand daraus abzurufen.
Wenn ich weiß, dass ich das erste Element haben möchte, kann ich es verwenden set.iterator().next()
, aber ansonsten muss ich es anscheinend in ein Array umwandeln, um ein Element an einem bestimmten Index abzurufen.
Was sind die geeigneten Methoden zum Abrufen von Daten aus einem Satz? (außer mit einem Iterator)
Ich bin sicher, dass 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 hier und einige sagen "mehr Kontext". Das spezifische Szenario war ein dbUnit-Test, bei dem ich vernünftigerweise behaupten konnte, dass der von einer Abfrage zurückgegebene Satz nur 1 Element enthielt, und ich versuchte, auf dieses Element zuzugreifen.
Die Frage ist jedoch ohne das Szenario zutreffender, da sie fokussierter bleibt:
Was ist der Unterschied zwischen Soll- und Liste .
Vielen Dank an alle für die fantastischen Antworten unten.
quelle
Antworten:
Weil Sets keine Bestellung haben. Einige Implementierungen tun dies (insbesondere diejenigen, die die
java.util.SortedSet
Schnittstelle implementieren ), aber das ist keine allgemeine Eigenschaft von Mengen.Wenn Sie versuchen, Sets auf diese Weise zu verwenden, sollten Sie stattdessen eine Liste verwenden.
quelle
Tatsächlich ist dies eine wiederkehrende Frage beim Schreiben von JavaEE-Anwendungen, die Object-Relational Mapping verwenden (z. B. mit Hibernate). und von allen 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 bestellte UND eindeutige Daten benötigen) und schlug das SortedSet vor, aber dies ist nicht das, was Marty Pitt wirklich brauchte.
Dieses "IndexedSet" ist NICHT dasselbe wie ein SortedSet - in einem SortedSet werden die Elemente mithilfe eines Komparators (oder anhand ihrer "natürlichen" Reihenfolge) sortiert.
Stattdessen ist es näher an einem LinkedHashSet (was auch andere vorgeschlagen haben) oder noch mehr an einem (ebenfalls nicht vorhandenen) "ArrayListSet", da es garantiert, dass die Elemente in der Reihenfolge zurückgegeben werden, in der sie eingefügt wurden.
Aber das LinkedHashSet ist eine Implementierung, keine Schnittstelle! Was benötigt wird, ist eine IndexedSet (oder ListSet oder OrderedSet oder UniqueList) Schnittstelle! Auf diese Weise 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 endlich in Java 7 enthalten sein ...
quelle
ListOrderedSet
das, was das OP vor 7 Jahren brauchte (und ich brauchte es heute).What is needed is an IndexedSet (or ListSet, or OrderedSet, or UniqueList)...
und ignoriert...interface
. Das tut mir leid!Fügen Sie nur einen Punkt hinzu, der in der Antwort von mmyers nicht erwähnt wurde .
Sie sollten sich auch mit der
SortedSet
Schnittstelle vertraut machen (deren häufigste Implementierung istTreeSet
).Ein SortedSet ist ein Set (dh Elemente sind eindeutig), das durch die natürliche Reihenfolge der Elemente oder durch Verwendung einiger Elemente geordnet bleibt
Comparator
. Sie können einfach mitfirst()
undlast()
Methoden auf das erste und letzte Element zugreifen . A ist von ZeitSortedSet
zu Zeit nützlich, wenn Sie Ihre Sammlung sowohl duplikationsfrei als auch auf bestimmte Weise bestellt halten müssen.Bearbeiten : Wenn Sie ein Set benötigen, dessen Elemente in Einfügereihenfolge gehalten werden (ähnlich wie bei einer Liste), schauen Sie sich das an
LinkedHashSet
.quelle
Diese Art von führt zu der Frage, wann Sie ein Set verwenden sollten und wann Sie eine Liste verwenden sollten. Normalerweise lautet der Rat:
Ein vierter Fall, der häufig auftritt, ist, dass Sie keine benötigen. In diesem Fall sehen Sie einige Programmierer mit Listen und einige mit Sets. Persönlich finde ich es sehr schädlich, Set als Liste ohne Bestellung zu sehen - weil es wirklich ein ganz anderes Tier ist. Bevorzugen Sie immer Listen, es sei denn, Sie benötigen Dinge wie Eindeutigkeit oder Gleichheit.
quelle
Ich bin nicht sicher, ob jemand es genau so geschrieben hat, aber Sie müssen Folgendes verstehen:
Es gibt kein "erstes" Element in einer Menge.
Denn wie andere gesagt haben, haben Sets keine Bestellung. Eine Menge ist ein mathematisches Konzept, das speziell keine Bestellung enthält.
Natürlich kann Ihr Computer nicht wirklich eine Liste von Dingen speichern, die nicht im Speicher bestellt sind. Es muss etwas bestellt werden. Intern ist es ein Array oder eine verknüpfte Liste oder so. Aber Sie wissen nicht wirklich, was es ist, und es hat nicht wirklich ein erstes Element; Das Element, das "zuerst" herauskommt, kommt zufällig auf diese Weise heraus und ist möglicherweise beim nächsten Mal 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 mit dem, was Sie getan haben. Tatsächlich kennen Sie die von Ihnen verwendete Implementierung möglicherweise nicht so gut wie Sie denken.
Die Leute stoßen auf dieses ALL. DAS. ZEIT. mit RDBMS-Systemen und nicht verstehen. Eine RDBMS-Abfrage gibt eine Reihe von Datensätzen zurück. Dies ist der gleiche Satztyp aus der Mathematik: eine ungeordnete Sammlung von Elementen, nur in diesem Fall handelt es sich bei den Elementen um Datensätze. Ein RDBMS-Abfrageergebnis hat überhaupt keine garantierte Reihenfolge, es sei denn, Sie verwenden die ORDER BY-Klausel, aber die Leute gehen davon aus, dass dies der Fall ist, und stolpern eines Tages, wenn sich die Form ihrer Daten oder ihres Codes geringfügig ändert und der Abfrageoptimierer funktioniert auf eine andere Weise und plötzlich kommen die Ergebnisse nicht in der erwarteten Reihenfolge heraus. Dies sind normalerweise die Personen, die in der Datenbankklasse (oder beim Lesen der Dokumentation oder der Tutorials) nicht darauf geachtet haben, als ihnen im Vorfeld erklärt wurde, dass die Abfrageergebnisse keine garantierte Reihenfolge haben.
quelle
Set
istIterable
.In den Standard-Java-Sammlungen fehlen einige Datenstrukturen.
Tasche (wie Set, kann aber mehrfach Elemente 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, sind Sie möglicherweise an Google Collections interessiert
quelle
Das stimmt, Elemente in Set sind per Definition der Set-Sammlung nicht geordnet. Sie können also nicht über einen Index aufgerufen werden.
Aber warum haben wir keine get (Objekt) -Methode, nicht indem wir den Index als Parameter angeben, sondern ein Objekt, das dem gesuchten Objekt entspricht? Auf diese Weise können wir auf die Daten des Elements innerhalb der Menge zugreifen, indem wir nur die Attribute kennen, die von der Methode equal verwendet werden.
quelle
Wenn Sie in einem Satz viele zufällige Zugriffe nach Index ausführen, können Sie eine Array-Ansicht der Elemente abrufen:
Es gibt jedoch zwei Hauptnachteile:
quelle
Dies liegt daran, dass Set nur die Eindeutigkeit garantiert, aber nichts über die optimalen Zugriffs- oder Verwendungsmuster aussagt. Das heißt, ein Set kann eine Liste oder eine Karte sein, von denen jede sehr unterschiedliche Abrufeigenschaften aufweist.
quelle
Der einzige Grund, warum ich mir vorstellen kann, einen numerischen Index in einer Menge zu verwenden, ist die Iteration. Verwenden Sie dazu
quelle
Ich bin auf Situationen gestoßen, in denen ich tatsächlich ein sortiertes Set mit Zugriff über den Index haben wollte (ich stimme anderen Postern zu, 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 nicht erlaubt sind.
Ich brauchte den Zugriff über den Index, um sie anzuzeigen, und die festgelegten Attribute waren praktisch, um Duplikate effizient zu entfernen.
Da ich in java.util oder in Google-Sammlungen keine geeignete Sammlung gefunden habe, war es für mich unkompliziert, sie selbst zu implementieren. Die Grundidee besteht darin, ein SortedSet zu verpacken und eine Liste zu erstellen, wenn der Zugriff über den Index erforderlich ist (und die Liste zu vergessen, wenn das SortedSet geändert wird). Dies funktioniert natürlich nur dann effizient, wenn das umschlossene SortedSet geändert wird und der Zugriff auf die Liste während der Lebensdauer der Sammlung getrennt wird. Ansonsten verhält es sich wie eine Liste, die oft sortiert wird, dh zu langsam.
Bei einer großen Anzahl von Kindern hat sich die Leistung gegenüber einer Liste, die ich über Collections.sort sortiert habe, erheblich verbessert.
quelle
Bitte beachten Sie, dass über den Index nur auf 2 grundlegende Datenstrukturen zugegriffen werden kann.
O(1)
zeitlicher Komplexität zugegriffen werden , um eineget(int index)
Operation zu erreichen .O(n)
zeitlicher Komplexität, um denget(int index)
Betrieb zu erreichen .Wird in Java
ArrayList
mithilfe der Array- Datenstruktur implementiert .Während Set Strukturdaten in der Regel über implementiert werden können HashTable / HashMap oder BalancedTree Datenstruktur für die schnelle Erkennung , ob ein Element nicht vorhandenes Element vorhanden ist, und fügen Sie , in der Regel ein gut umgesetzt Set erreichen kann
O(1)
Zeitkomplexitätcontains
Betrieb. In JavaHashSet
ist dies die am häufigsten verwendete Implementierung von Set . Sie wird durch Aufrufen derHashMap
APIHashMap
implementiert und mithilfe einer separaten Verkettung mit verknüpften Listen (eine Kombination aus Array und LinkedList ) implementiert .Da Set über unterschiedliche Datenstrukturen implementiert werden kann, gibt es dafür keine
get(int index)
Methode.quelle
Data.Sequence.lookup
Funktion) ermöglichen auch den Zugriff über den Index ( genauer gesagtO(1)
in der Nähe der EndenO(log n)
in der Nähe der MitteO(min(log(k), log(n-k)))
), auch Binärbäume (siehe Haskell-Data.Set.lookupIndex
Funktion). Ihre anfängliche Behauptung, dass "Bitte beachten Sie, dass nur auf 2 grundlegende Datenstrukturen über den Index zugegriffen werden kann", ist daher nicht korrekt.Der Grund, warum die Set- Schnittstelle keinen Aufruf vom Typ get index oder etwas noch grundlegenderes wie first () oder last () hat, liegt darin, dass es sich um eine mehrdeutige Operation handelt und daher eine potenziell gefährliche Operation. Wenn eine Methode einen Satz zurückgibt und Sie beispielsweise die Methode first () aufrufen, was ist das erwartete Ergebnis, da ein generischer Satz keine Garantie für die Bestellung übernimmt? Das resultierende Objekt kann sehr gut zwischen den einzelnen Aufrufen der Methode variieren, oder es kann nicht dazu führen, dass Sie in ein falsches Sicherheitsgefühl versetzt werden, bis die von Ihnen verwendete Bibliothek die darunter liegende Implementierung ändert und Sie nun feststellen, dass Ihr gesamter Code für 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 Satz, da a) keine Garantie für die Bestellung besteht und b) keine Garantie dafür besteht, dass sich die Reihenfolge bei nachfolgenden Aufrufen oder bei anderen zugrunde liegenden Implementierungen nicht ändert. Wenn Sie etwas dazwischen benötigen, ist ein SortedSet oder ein LinkedHashSet das, was Sie wollen.
// Ich wünschte, die Set-Schnittstelle hätte ein get-random-Element.
quelle
java.util.Set
ist eine Sammlung von nicht bestellten Artikeln. Es macht keinen Sinn, wenn das Set einen get (int-Index) hat, da Set keinen Index hat und Sie auch nur den Wert erraten können.Wenn Sie dies wirklich wollen, codieren Sie eine Methode, um ein zufälliges Element aus Set zu erhalten.
quelle
Du kannst tun
new ArrayList<T>(set).get(index)
quelle
new ArrayList<T>(t).get(0)
Ich denke, es gibt einen berechtigten Widerspruch gegen die Idee, ein bestimmtes Element aus einer Menge durch einen Index zu erhalten. Es wäre jedoch schön, wenn Set eine nur () -Mitgliedsfunktion hätte, die für Sets der Größe 1 einen einfachen Zugriff auf das einzige Element im Set ermöglicht. Dies würde die oben genanntennew ArrayList
oderfor (Foo foo : foos) { return foo; }
Wenn Ihnen das zu sortierende Set nichts ausmacht, können Sie sich das Projekt mit der indizierten Baumkarte ansehen .
Das erweiterte TreeSet / TreeMap bietet Zugriff auf Elemente durch Index oder Abrufen des Index eines Elements. Die Implementierung basiert auf der Aktualisierung der Knotengewichte im RB-Baum. Also keine Iteration oder Sicherung durch eine Liste hier.
quelle
Set ist eine Schnittstelle und einige seiner Implementierungsklassen sind HashSet, TreeSet und LinkedHashSet. Es verwendet HashMap unter der Haube, um Werte zu speichern. Da HashMap die Reihenfolge nicht beibehält, ist es nicht möglich, den Wert per Index abzurufen.
Sie müssen jetzt darüber nachdenken, wie Set HashMap verwendet, da HashMap ein Schlüssel-Wert-Paar speichert, das Set jedoch nicht. gültige Frage. Wenn Sie ein Element intern in Set hinzufügen, wird eine HashMap verwaltet, in der der Schlüssel das Element ist, das Sie in Set eingeben möchten, und der Wert die Dummy-Konstante ist. Unten finden Sie eine interne Implementierung der Add-Funktion. Daher haben alle Schlüssel in der HashMap den gleichen konstanten Wert.
quelle
Set
Implementierungen werdenHashMap
unter der Haube verwendet, um Werte zu speichern. Können Sie diesen Anspruch begründenTreeSet
?the keys in the HashMap will have the same constant value
Die Schlüssel imHashMap
Testament werden ein und derselben unveränderlichenObject
Um ein Element in einem Set zu erhalten, verwende ich Folgendes:
quelle
T
definiert? Warumif (true)
?