Ich versuche, eine Wörterbuch-Nachschlagetabelle in C # zu erstellen. Ich muss ein 3-Tupel von Werten in eine Zeichenfolge auflösen. Ich habe versucht, Arrays als Schlüssel zu verwenden, aber das hat nicht funktioniert, und ich weiß nicht, was ich sonst tun soll. An dieser Stelle denke ich darüber nach, ein Wörterbuch mit Wörterbüchern zu erstellen, aber das wäre wahrscheinlich nicht sehr hübsch anzusehen, obwohl ich es so in Javascript machen würde.
c#
dictionary
hashtable
tuples
AlexH
quelle
quelle
GetHashCode
Implementierung ist nicht sehr gut. Es ist unter Permutation der Felder unveränderlich.new object()
sollte ein anderer gleich seinnew object()
? Es wird nicht nur ein direkter Referenzvergleich verwendet ... versuchen Sie:bool test = new Tuple<int, string>(1, "foo").Equals(new Tuple<int, string>(1, "Foo".ToLower()));
Zwischen auf Tupeln und verschachtelten Wörterbüchern basierenden Ansätzen ist es fast immer besser, sich für Tupel zu entscheiden.
Von Wartbarkeit Sicht ,
Es ist viel einfacher, eine Funktionalität zu implementieren, die wie folgt aussieht:
als
von der Angerufenen Seite. Im zweiten Fall erfordert jede Hinzufügung, Suche, Entfernung usw. eine Aktion für mehr als ein Wörterbuch.
Wenn Ihr zusammengesetzter Schlüssel in Zukunft ein weiteres (oder weniger) Feld benötigt, müssen Sie im zweiten Fall (verschachteltes Wörterbuch) den Code erheblich ändern, da Sie weitere verschachtelte Wörterbücher und nachfolgende Überprüfungen hinzufügen müssen.
Aus Sicht der Leistung ist die beste Schlussfolgerung, die Sie erzielen können, die Messung selbst. Es gibt jedoch einige theoretische Einschränkungen, die Sie im Voraus berücksichtigen können:
Im Fall eines verschachtelten Wörterbuchs hat ein zusätzliches Wörterbuch für jeden Schlüssel (außen und innen) einen gewissen Speicheraufwand (mehr als das Erstellen eines Tupels).
Im Fall eines verschachtelten Wörterbuchs muss jede grundlegende Aktion wie Hinzufügen, Aktualisieren, Nachschlagen, Entfernen usw. in zwei Wörterbüchern ausgeführt werden. Jetzt gibt es einen Fall, in dem der Ansatz eines verschachtelten Wörterbuchs schneller sein kann, dh wenn die nachgeschlagenen Daten nicht vorhanden sind, da die Zwischenwörterbücher die vollständige Berechnung und den Vergleich des Hashcodes umgehen können. Andererseits sollte dies zeitlich festgelegt werden, um sicherzugehen. Bei Vorhandensein von Daten sollte diese langsamer sein, da die Suche zweimal (oder je nach Verschachtelung dreimal) durchgeführt werden sollte.
In Bezug auf den Tupel-Ansatz sind .NET-Tupel nicht die leistungsstärksten, wenn sie als Schlüssel in Mengen verwendet werden sollen, da ihre Implementierung
Equals
undGetHashCode
das Boxen ein Boxen für Werttypen verursacht .Ich würde mich für ein Tupel-basiertes Wörterbuch entscheiden, aber wenn ich mehr Leistung möchte, würde ich mein eigenes Tupel mit besserer Implementierung verwenden.
Nebenbei bemerkt, nur wenige Kosmetika können das Wörterbuch cool machen:
Aufrufe im Indexer-Stil können viel sauberer und intuitiver sein. Zum Beispiel
Stellen Sie daher die erforderlichen Indexer in Ihrer Wörterbuchklasse bereit, die die Einfügungen und Suchvorgänge intern verarbeiten.
Implementieren Sie außerdem eine geeignete
IEnumerable
Schnittstelle und stellen Sie eineAdd(TypeA, TypeB, TypeC, string)
Methode bereit , mit der Sie die Syntax für die Initialisierung von Sammlungen erhalten, z.quelle
string foo = dict[a][b][c]
?a
. Sie können einfach jedes Wörterbuch wie jede normale Sammlung iterieren und nach Schlüsseleigenschaften suchen, falls dies der Fall ista
. Wenn Sie das Element immer durch die erste Eigenschaft in diktieren möchten, können Sie das Wörterbuch besser als Wörterbuch der Wörterbücher entwerfen, wie in meiner Antwort und Abfrage wie gezeigtdict[a]
, wodurch Sie ein anderes Wörterbuch erhalten.4
für beide Schlüssela
und erhalten möchtenb
, können Sie ihn zu einem Standardwörterbuch machen und Werte wiedict[a] = 4
und hinzufügendict[b] = 4
. Es ist möglicherweise nicht sinnvoll, wenn logischerweise Ihrea
undb
eine Einheit sein sollte. In einem solchen Fall können Sie einen Benutzer definieren,IEqualityComparer
der zwei Schlüsselinstanzen als gleich gleichsetzt, wenn eine ihrer Eigenschaften gleich ist. All dies kann generisch mit Reflexion erfolgen.Wenn Sie sich in C # 7 befinden, sollten Sie Wertetupel als zusammengesetzten Schlüssel verwenden. Wertetupel bieten normalerweise eine bessere Leistung als die herkömmlichen Referenztupel (
Tuple<T1, …>
), da Wertetupel Werttypen (Strukturen) und keine Referenztypen sind, sodass die Kosten für die Speicherzuweisung und die Speicherbereinigung vermieden werden. Außerdem bieten sie eine übersichtlichere und intuitivere Syntax, sodass ihre Felder auf Wunsch benannt werden können. Sie implementieren auch dieIEquatable<T>
für das Wörterbuch erforderliche Schnittstelle.quelle
Die guten, sauberen, schnellen, einfachen und lesbaren Wege sind:
füge so etwas hinzu:
So können Sie es mit Wörterbuch verwenden:
quelle
public TypeA DataA => Item1;
Wenn Sie aus irgendeinem Grund wirklich vermeiden möchten, eine eigene Tuple-Klasse zu erstellen oder in .NET 4.0 zu verwenden, ist ein anderer Ansatz möglich. Sie können die drei Schlüsselwerte zu einem einzigen Wert zusammenfassen.
Wenn die drei Werte beispielsweise ganzzahlige Typen sind, die zusammen nicht mehr als 64 Bit benötigen, können Sie sie zu einem kombinieren
ulong
.Im schlimmsten Fall können Sie immer eine Zeichenfolge verwenden, solange Sie sicherstellen, dass die drei darin enthaltenen Komponenten durch ein Zeichen oder eine Sequenz begrenzt sind, die nicht in den Komponenten des Schlüssels vorkommen, z. B. mit drei Zahlen, die Sie versuchen könnten:
Dieser Ansatz ist offensichtlich mit einem gewissen Kompositionsaufwand verbunden, aber je nachdem, wofür Sie ihn verwenden, kann dies trivial genug sein, um sich nicht darum zu kümmern.
quelle
JavaScriptSerializer
um ein Array von Zeichenfolgen- und / oder Ganzzahltypen für Sie zu verketten . Auf diese Weise müssen Sie sich kein Trennzeichen selbst einfallen lassen.key1
,key2
,key3
) waren Saiten die deliminator (mit"#"
)Ich würde Ihr Tupel mit einem richtigen GetHashCode überschreiben und es einfach als Schlüssel verwenden.
Solange Sie die richtigen Methoden überladen, sollten Sie eine anständige Leistung sehen.
quelle
Hier ist das .NET-Tupel als Referenz:
quelle
Wenn Ihr konsumierender Code mit einer IDictionary <> -Schnittstelle anstelle von Dictionary auskommen kann, wäre mein Instinkt gewesen, ein SortedDictionary <> mit einem benutzerdefinierten Array-Vergleicher zu verwenden, dh:
Und erstellen Sie so (mit int [] nur als konkretes Beispiel):
quelle