So wählen Sie einen zufälligen Schlüssel aus einer HashMap in Java?
Arbeite ich mit einem großen ArrayList<HashMap<A,B>>
, und ich würde immer wieder brauchen, wählen Sie einen zufälligen Schlüssel aus einer zufälligen HashMap (und einige Sachen mit ihm). Die Auswahl der zufälligen HashMap ist trivial, aber wie soll ich wählen Sie eine zufällige Taste in dieser HashMap?
Geschwindigkeit wichtig ist (als ich dies tun müssen 10000 mal und die hashmaps sind groß), so dass nur wählen eine zufällige Zahl k in [0,9999] und dann tut .next()
auf der iterator k-mal, das ist nicht wirklich eine option. Ähnlich, die Umwandlung der HashMap in ein array oder ArrayList auf jede zufällige Holen, das ist nicht wirklich eine option. Bitte, Lesen Sie diese, bevor Sie Antworten.
Technisch fühle ich, dass dies möglich sein sollte, da die HashMap speichert seine Schlüssel in einer Entry[]
intern, und die Auswahl nach dem Zufallsprinzip aus einem array einfach ist, aber ich kann nicht herausfinden, wie Zugriff auf diese Entry[]
. Also, irgendwelche Ideen auf das interne Entry[]
sind mehr als willkommen. Andere Lösungen (solange Sie nicht verbrauchen die lineare Zeit in der hashmap-Größe) sind auch willkommen natürlich.
Hinweis: Heuristiken sind in Ordnung, wenn es also eine Methode, schließt die 1% der Elemente (z.B. wegen multi-gefüllte Eimer) das ist überhaupt kein problem.
- Einträge angekettet werden, wenn Sie mehr als eine zur gleichen index. So, dass wäre nicht so einfach.
- Wenn die Umwandlung den entrySet zu einer Liste ist'f schnell genug ist (hast du das Profil ?), dann müssen Sie eine weitere Datenstruktur.
- Pseudo ist in Ordnung, wenn es 1% der Einträge, die nie abgeholt werden, ist dies keine große Sache. Nicht, dass geben zusätzliche Optionen? Also, keine sorgen, wenn ein element verkettet ist, dann wählen Sie einfach ein anderes element.
Du musst angemeldet sein, um einen Kommentar abzugeben.
aus der Spitze von meinem Kopf
dann nur
Entry[]
ich könnte natürlich einfach eine einfache änderung in das array, aber es scheint, dass dieseEntry[]
nicht zugänglich ist (es sei denn ich kopieren und fügen Sie den gesamten source-code).Benötigen Sie Zugriff auf die zugrunde liegende Tabelle.
Diese noch Durchlaufen muss, die Einträge zu finden, das ist so der worst-case ist O(n), sondern das typische Verhalten ist O(1).
HashMap.class.getDeclaredField("table");
, genial, danke! Alle, die ich bin Links zu Fragen, mit jetzt ist, warum Sie nicht setzen Sie dieses in HashMap und HashSet standardmäßig. 🙂Habe ich es geschafft eine Lösung zu finden, ohne performance-Verlust. Ich werde es hier posten, da kann es helfen, anderen Menschen-und möglicherweise beantworten mehrere offene Fragen zu diesem Thema (ich Suche für diese später).
Was Sie brauchen, ist eine zweite benutzerdefinierte
Set
-wie Datenstruktur, die zum speichern der Schlüssel-nicht eine Liste, wie einige hier vorgeschlagen. Listen-Daten-Strukturen sind zu teuer, um Elemente zu entfernen aus. Die erforderlichen Operationen sind das hinzufügen/entfernen von Elementen in konstanter Zeit (zu halten Sie up-to-date mit der HashMap) und ein Verfahren zu wählen, das zufällige element. Die folgende KlasseMySet
tut genau diesindexOf
Methode?Klingt wie Sie sollten entweder eine untergeordnete Liste mit den Tasten oder ein reales Objekt, nicht eine Karte, die zum speichern in der Liste.
Entry[]
. Ich kann copy-paste der gesamte Quellcode in eine neue Datei und verwenden Sie es dort, aber das ist nicht wirklich guten coding style. :/Ich nehme an, Sie sind mit
HashMap
wie müssen Sie Aussehen, bis zu einem späteren Datum?Wenn das nicht der Fall, dann ändern Sie einfach Ihre
HashMap
zu einemArray
/ArrayList
.Wenn dies der Fall ist, warum nicht speichern Sie Ihre Objekte in einer
Map
UND einArrayList
so kann man zufällig oder durch die-Taste.Alternativ könnten Sie verwenden ein
TreeMap
stattHashMap
? Ich weiß nicht, was geben Sie Ihren Schlüssel aber Sie verwendenTreeMap.floorKey()
in Verbindung mit einigen der wichtigsten randomizer.Nach einiger Zeit, kam ich zu dem Schluss, dass Sie brauchen, um ein Modell zu erstellen, das kann unterstützt werden durch eine
List<Map<A, B>>
und einList<A>
zu halten Ihre Schlüssel. Sie benötigen, um den Zugriff auf IhreList<Map<A, B>>
undList<A>
einfach die Operationen/Methoden an den Aufrufer. Auf diese Weise haben Sie die volle Kontrolle über die Implementierung, und die eigentlichen Objekte werden sicherer aus externen Veränderungen.Btw, deine Fragen führen mich zu,
values()
Methode liefert auchSet
.Diesem Beispiel IndexedSet, kann geben Ihnen eine Idee über, wie.
[bearbeitet]
Dieser Klasse, SetUniqueList, könnte Ihnen helfen, wenn Sie sich entscheiden, erstellen Sie Ihr eigenes Modell. Es besagt ausdrücklich, dass es umhüllt den
list
(keine Kopien). Also, ich denke, wir können etwas tun,Hinweis: ich nicht es selber auszuprobieren. Wird das auch später machen (hetzen, zu Hause).
Seit Java 8 gibt es eine O(log(N)) - Ansatz mit O(log(N)) zusätzliche memory: erstellen Sie eine
Spliterator
übermap.entrySet().spliterator()
machen log(map.size())trySplit()
Anrufe und wählen Sie entweder die erste oder die zweite Hälfte nach dem Zufallsprinzip. Wenn es sagen wir weniger als 10 Elemente, die Links in einemSpliterator
, steckt Sie in eine Liste und machen Sie eine zufällige Holen.trySplit()
teilen Sie immer in der Hälfte oder was? Ich bin verwirrt über das Innenleben dieser neuen routine.Wenn du unbedingt Zugriff auf den array-Eintrag in der HashMap, die Sie verwenden können, Reflexion. Aber dann wird Ihr Programm sein, abhängig von der konkreten Implementierung der HashMap.
Wie vorgeschlagen, können Sie halten eine separate Liste der Schlüssel, die für jede Karte. Sie würde nicht halten, tief Kopien der Schlüssel, so dass der tatsächliche Speicher, der entnormierung wäre nicht so groß.
Dritte Ansatz ist die Implementierung eigener Map-Implementierung, die einem immer, dass keys in einer Liste statt einem Satz.
Wie etwa Verpackung HashMap in eine andere Implementierung von Map? Die andere Karte verwaltet eine Liste, und auf der put() es gilt:
(Ich gehe davon aus, dass null-Werte nicht zulässig, wenn Sie verwenden, containsKey, aber das ist langsamer)