Gibt es eine Möglichkeit, verschachtelte Sammlungen eleganter zu behandeln?

8

Meine Frage ist eher eine Designfrage. In meinem Programm bin ich zu einer Datenstruktur gekommen, die ungefähr so ​​aussieht:

private ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>> services  = new ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>>();

Gibt es eine Möglichkeit, mit einer solchen Datenstruktur eleganter umzugehen? Vielen Dank!

Bearbeiten : A, B und C sind Geschäftsklassen. Eine A-Instanz "kann" (als Assoziation) viele Bs haben und ein B "kann" viele Zuordnungen Integer-C haben.

ovdsrn
quelle
Welche Arten sind A, Bund C? Es wäre einfacher zu beantworten, wenn ich die Bedeutung der dreistufigen Verschachtelung Ihrer Karten verstehen könnte.
Dasblinkenlight
1
Ohne etwas über die Domain zu wissen, glaube ich nicht, dass es eine allgemeine Lösung gibt. Abhängig davon, wie die Karten verwendet werden, können Sie eine oder mehrere der Karten durch Klassen ersetzen, die einen bestimmten Satz von Eigenschaften exportieren.
Ernest Friedman-Hill
4
Ziehen Sie in Betracht, Objekte zu verwenden, die Verhalten einkapseln, anstatt dumme Datenstrukturen. Jede dieser Karten sollte wahrscheinlich in ein bestimmtes Objekt eingewickelt werden.
Müssen Sie wirklich ConcurrentHashMaps auf jeder Verschachtelungsebene verwenden?
Russell
@ ErnestFriedman-Hill: Ich dachte, dass es so sein könnte - dass es keine "allgemeine Lösung" gibt, nur eine geschäftsbezogene.

Antworten:

16

Erstellen Sie eine Klasse Triplemit Feldern für A, B, Integer, überschreiben hashCode()und equals(), und die Verwendung Map<Triple,C>anstelle vonMap<A,Map<B,Map<Integer,C>>>

Bei diesem Ansatz fügen Sie alle Elemente in einer Karte mit einem größeren möglichen Tastenbereich zusammen.

amit
quelle
Wird der Downvoter erklären? Ich nahm an, dass das OP tatsächlich versucht, Folgendes zuzuordnen: (A,B,Integer)-> Cund damit die verschachtelte MapVerwendung. Die Bearbeitung unterstützt auch meine Vorahnung.
Amit
2
Richtig, das ist es, was ich versuche zuzuordnen: (A, B, Integer) auf C.
Ich werde auch hinzufügen, der Triple-Klasse etwas Bedeutendes in Ihrer Geschäftsdomäne nennen. Es muss etwas bedeuten :-)
Martijn Verburg
Aufgrund des Vertrags von equalsfunktioniert dies nur, wenn die Schlüssel eine Äquivalenzbeziehung bilden. Ich bin kürzlich auf eine Situation wie diese gestoßen, in der dies nicht der Fall war: Die dritte Komponente des Schlüssels könnte entweder ein Standardwert sein, der eine beliebige Instanz akzeptiert, oder ein konkreter Wert, wobei sich alle konkreten Werte voneinander unterscheiden. Daher müsste jeder konkrete Wert als gleich dem Standardwert angesehen werden, und durch die Transitivität müssten sie alle gleich sein, was sie nicht waren.
G. Bach
6

[Ich komme aus dem C # -Hintergrund, aber die Antwort sollte zutreffen]

[Es spielt keine große Rolle, aber ich gehe davon aus, dass das letzte Element ConcurrentHashMap <C, Integer> ist. ]

Sie haben eine Funktion f vom Typ A -> (B -> (C -> int)) Wenn es wirklich das ist, was Sie brauchen, habe ich keine Antwort parat. Aber vielleicht würde eine Funktion f vom Typ (A x B x C) -> int für Ihre Zwecke ausreichen.

Der Unterschied zwischen zwei Fällen besteht darin, dass der erste fauler, funktionaler, wohl eleganter ist und es möglich ist, eine "teilweise angewendete" Funktion zu haben. Zum Beispiel haben Sie ein a- Element (vom Typ A), Sie wenden a auf f an und haben eine Funktion g vom Typ (B -> (C -> int)) , die Sie weitergeben, an Methoden senden können, was auch immer. Es ist jedoch etwas umständlich und etwas mehr Code, um die Funktion richtig zu initialisieren.

Die zweite ist eifriger und weniger elegant, aber möglicherweise einfacher zu codieren und zu verstehen. Alles, was Sie tun müssen, ist eine generische Klasse Triple <A, B, C> , die Equals () und GetHashCode () überschreibt, damit sie eine Wertesemantik aufweist (zwei Instanzen sind als gleich anzusehen, wenn sie gleiche Elemente haben). und deklarieren Sie, dass die ConcurrentHashMap von Triple bis Integer ist . Die offensichtlichsten Kosten sind, dass Sie die Elemente A , B , C auf einmal bereithalten müssen, um eine Instanz von Triple zu erstellen und die Suche durchzuführen.

Bearbeiten: Wenn das letzte Element wirklich ConcurrentHashMap <C, Integer> ist , hat Ihre generische Klasse A- , B- und Integer- Felder, und die Zuordnung erfolgt von Triple <A, B, Integer> zu C.

Ali
quelle
Nennen Sie es vielleicht Triplestatt MyClasszu klären; Es gibt auch N-Tupel-Implementierungen im Web, wenn Sie wirklich faul sind.
Eigentlich ist die letzte Karte ConcurrentHashMap <Integer, C>, nicht ConcurrentHashMap <C, Integer>, aber es ist nur ein kleines Detail, da ich aus Ihrer Antwort sehe, dass Sie es richtig verstanden haben.
ovdsrn