Beste Implementierung für die Datenstruktur von Schlüsselwertpaaren?

74

Also habe ich mich in letzter Zeit ein bisschen mit C # beschäftigt, und alle generischen Sammlungen haben mich ein wenig verwirrt. Angenommen, ich wollte eine Datenstruktur darstellen, in der der Kopf eines Baums ein Schlüsselwertpaar war, und dann gibt es eine optionale Liste von Schlüsselwertpaaren darunter (aber nicht mehr Ebenen als diese). Wäre das geeignet?

public class TokenTree
{
    public TokenTree()
    {
        /* I must admit to not fully understanding this,
         * I got it from msdn. As far as I can tell, IDictionary is an
         * interface, and Dictionary is the default implementation of
         * that interface, right?
         */
        SubPairs = new Dictionary<string, string>();
    }

    public string Key;
    public string Value;
    public IDictionary<string, string> SubPairs;
}

Es ist wirklich nur ein einfacher Shunt zum Weitergeben von Daten.

Bernard
quelle

Antworten:

137

Es gibt einen tatsächlichen Datentyp namens KeyValuePair, der wie folgt verwendet wird

KeyValuePair<string, string> myKeyValuePair = new KeyValuePair<string,string>("defaultkey", "defaultvalue");
Adam Haile
quelle
1
Dies funktioniert hervorragend mit einer "using" -Anweisung (ähnlich dem alten typedef), um einige Eingaben zu sparen und alles klarer zu machen. Wenn Sie ständig zB das Paar (String, String) verwenden.
Andreas Reiff
8
KeyValuePair <Zeichenfolge, Zeichenfolge> NAME_HERE = neues KeyValuePair <Zeichenfolge, Zeichenfolge> ("Standardschlüssel", "Standardwert");
HasanAboShally
1
So erweitern Sie den Kommentar von @AndreasReiff: using NameValuePair = System.Collections.Generic.KeyValuePair<string, string>;oben in jeder Datei, die eine (string, string)Struktur benötigt. Obwohl ich es bequemer fand, ein class NameValuePairin meinem Namespace zu erstellen : public class NameValuePair { KeyValuePair<string, string> it; public NameValuePair( string name, string value ) { it = new KeyValuePair<string, string>( name, value ); } public string Name { get { return it.Key; } } public string Value { get { return it.Value; } } }
ToolmakerSteve
12

Eine mögliche Möglichkeit besteht darin, das Dictionary-Objekt sofort zu verwenden und es dann einfach mit Ihren eigenen Änderungen zu erweitern:

public class TokenTree : Dictionary<string, string>
{
    public IDictionary<string, string> SubPairs;
}

Dies gibt Ihnen den Vorteil, dass Sie die IDictionary-Regeln für Ihren Schlüssel nicht durchsetzen müssen (z. B. Schlüsseleindeutigkeit usw.).

Und ja, du hast das Konzept des Konstruktors richtig verstanden :)

Jon Limjap
quelle
7

Ich denke, was Sie suchen könnten (als wörtliche Umsetzung Ihrer Frage), ist:

public class TokenTree
{
    public TokenTree()
    {
        tree = new Dictionary<string, IDictionary<string,string>>();
    }

    IDictionary<string, IDictionary<string, string>> tree; 
}

Sie haben in Ihrer Frage tatsächlich eine "Liste" von Schlüsselwerten angegeben, daher möchten Sie möglicherweise das Innere IDictionarymit einem:

IList<KeyValuePair<string, string>>
Shaun Austin
quelle
5

Es gibt einen integrierten KeyValuePair-Typ. Tatsächlich gibt Ihnen das IDictionary Zugriff darauf, wenn Sie darin iterieren.

Auch diese Struktur ist kaum ein Baum, einen repräsentativeren Namen zu finden, könnte eine gute Übung sein.

Münze
quelle
3

Nur eine Sache, die Sie hinzufügen sollten (obwohl ich glaube, dass Ihre Frage bereits von anderen beantwortet wurde). Im Interesse der Erweiterbarkeit (da wir alle wissen, dass dies irgendwann passieren wird) sollten Sie sich das zusammengesetzte Muster ansehen. Dies ist ideal für die Arbeit mit "baumartigen Strukturen".

Wie gesagt, ich weiß, dass Sie nur eine Unterebene erwarten, aber dies könnte für Sie wirklich nützlich sein, wenn Sie später ^ _ ^ erweitern müssen

Rob Cooper
quelle
2

@ Jay Mooney : Eine generische Dictionary-Klasse in .NET ist eigentlich eine Hash-Tabelle, nur mit festen Typen.

Der von Ihnen gezeigte Code sollte niemanden davon überzeugen, Hashtable anstelle von Dictionary zu verwenden, da beide Codeteile für beide Typen verwendet werden können.

Für Hashtabelle:

foreach(object key in h.keys)
{
     string keyAsString = key.ToString(); // btw, this is unnecessary
     string valAsString = h[key].ToString();

     System.Diagnostics.Debug.WriteLine(keyAsString + " " + valAsString);
}

Für Wörterbuch:

foreach(string key in d.keys)
{
     string valAsString = d[key].ToString();

     System.Diagnostics.Debug.WriteLine(key + " " + valAsString);
}

Verwenden Sie für die andere Version mit KeyValuePair einfach die nicht generische Version für Hashtable und die generische Version für Dictionary.

Es ist also in beide Richtungen genauso einfach, aber Hashtable verwendet Object sowohl für Schlüssel als auch für Wert. Dies bedeutet, dass Sie alle Werttypen einschließen und keine Typensicherheit haben. Dictionary verwendet generische Typen und ist daher besser.

Lasse V. Karlsen
quelle
1

Dictionary Class ist genau das, was Sie wollen, richtig.

Sie können das Feld direkt als Dictionary anstelle von IDictionary deklarieren, aber das liegt bei Ihnen.

Lasse V. Karlsen
quelle
1

Verwenden Sie so etwas:

class Tree < T > : Dictionary < T, IList< Tree < T > > >  
{  
}  

Es ist hässlich, aber ich denke, es wird dir geben, was du willst. Schade, dass KeyValuePair versiegelt ist.

Kokos
quelle