Frage

Gibt es in der .NET-Basisklassenbibliothek Wörterbuchklassen, die die Verwendung doppelter Schlüssel ermöglichen?Die einzige Lösung, die ich gefunden habe, besteht darin, beispielsweise eine Klasse wie diese zu erstellen:

Dictionary<string, List<object>>

Aber die tatsächliche Verwendung ist ziemlich irritierend.In Java glaube ich, dass eine MultiMap dies erreicht, kann aber in .NET kein Analogon finden.

War es hilfreich?

Lösung

Wenn Sie mit .NET 3.5, verwenden Sie die Lookup Klasse.

EDIT: Sie erstellen im Allgemeinen eine Lookup mit Enumerable.ToLookup . Dies davon ausgehen, dass Sie es nicht danach ändern müssen -. Aber ich finde der Regel das ist gut genug

Wenn das nicht Arbeit für Sie, ich glaube nicht, dass es im Rahmen irgendetwas ist, das helfen wird - und das Wörterbuch verwendet, ist so gut wie es geht: (

Andere Tipps

Die List-Klasse funktioniert eigentlich ganz gut für Schlüssel / Wert-Sammlungen Duplikate enthalten, wo Sie möchten über die Sammlung iterieren. Beispiel:

List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();

// add some values to the collection here

for (int i = 0;  i < list.Count;  i++)
{
    Print(list[i].Key, list[i].Value);
}

Hier ist ein Weg, dies zu tun, mit List >

public class ListWithDuplicates : List<KeyValuePair<string, string>>
{
    public void Add(string key, string value)
    {
        var element = new KeyValuePair<string, string>(key, value);
        this.Add(element);
    }
}

var list = new ListWithDuplicates();
list.Add("k1", "v1");
list.Add("k1", "v2");
list.Add("k1", "v3");

foreach(var item in list)
{
    string x = string.format("{0}={1}, ", item.Key, item.Value);
}

Ausgänge k1 = v1, k1 = v2, v3 k1 =

Wenn Sie Zeichenfolgen sowohl als Schlüssel als auch als Werte verwenden, können Sie verwenden System.Collections.Specialized.NameValueCollection, die über die Methode GetValues(string key) ein Array von String-Werten zurückgibt.

Ich kam gerade über die PowerCollections Bibliothek, die unter anderem eine Klasse namens Multidictionary enthält. Diese ordentlich hüllt diese Art von Funktionalität.

Sehr wichtige Hinweis bezüglich der Verwendung von Lookup:

Sie können durch Aufruf Lookup(TKey, TElement) auf ein Objekt eine Instanz einer ToLookup erstellen, die IEnumerable(T) implementiert

Es gibt keinen öffentlichen Konstruktor eine neue Instanz eines Lookup(TKey, TElement) zu erstellen. Darüber hinaus sind Lookup(TKey, TElement) Objekte unveränderlich, das heißt, Sie können nicht Elemente oder Schlüssel von einem Lookup(TKey, TElement) Objekt hinzuzufügen oder zu entfernen, nachdem es erstellt wurde.

(von MSDN)

Ich würde denken, dass dies ein Show-Stopper für die meisten Anwendungen wäre.

Ich denke, so etwas wie List<KeyValuePair<object, object>> den Job tun würde.

Wenn Sie mit> = .NET 4, dann können Sie Tuple Klasse verwenden:

// declaration
var list = new List<Tuple<string, List<object>>>();

// to add an item to the list
var item = Tuple<string, List<object>>("key", new List<object>);
list.Add(item);

// to iterate
foreach(var i in list)
{
    Console.WriteLine(i.Item1.ToString());
}

Hier finden Sie aktuelle rel="noreferrer"> HashBag Klasse.

Es ist leicht genug, um auf die Version eines Wörterbuchs „Ihre eigene Rolle“, die „doppelten Schlüssel“ Einträge ermöglicht. Hier ist eine grobe einfache Implementierung. Vielleicht möchten Sie Unterstützung prüfen, indem für im Grunde die meisten (wenn nicht alle) auf IDictionary<T>.

public class MultiMap<TKey,TValue>
{
    private readonly Dictionary<TKey,IList<TValue>> storage;

    public MultiMap()
    {
        storage = new Dictionary<TKey,IList<TValue>>();
    }

    public void Add(TKey key, TValue value)
    {
        if (!storage.ContainsKey(key)) storage.Add(key, new List<TValue>());
        storage[key].Add(value);
    }

    public IEnumerable<TKey> Keys
    {
        get { return storage.Keys; }
    }

    public bool ContainsKey(TKey key)
    {
        return storage.ContainsKey(key);
    }

    public IList<TValue> this[TKey key]
    {
        get
        {
            if (!storage.ContainsKey(key))
                throw new KeyNotFoundException(
                    string.Format(
                        "The given key {0} was not found in the collection.", key));
            return storage[key];
        }
    }
}

Ein kurzes Beispiel, wie man es verwenden:

const string key = "supported_encodings";
var map = new MultiMap<string,Encoding>();
map.Add(key, Encoding.ASCII);
map.Add(key, Encoding.UTF8);
map.Add(key, Encoding.Unicode);

foreach (var existingKey in map.Keys)
{
    var values = map[existingKey];
    Console.WriteLine(string.Join(",", values));
}

In Antwort auf die ursprüngliche Frage. So etwas wie Dictionary<string, List<object>> in einer Klasse namens MultiMap in The Code Project implementiert.

Sie können weitere Informationen auf den folgenden Link: http://www.codeproject.com/KB/cs/MultiKeyDictionary.aspx

Die Namevaluecollection unterstützt mehr String-Werte unter einem Schlüssel (der auch ein String ist), aber es ist das einzige Beispiel, das ich mir bewusst bin.

Ich neige dazu, Konstrukte zu erzeugen, ähnlich der in Ihrem Beispiel, wenn ich Situationen laufe in dem ich diese Art von Funktionalität benötigen.

Wenn die List<KeyValuePair<string, object>> Option verwenden, können Sie LINQ verwenden, um die Suche zu tun:

List<KeyValuePair<string, object>> myList = new List<KeyValuePair<string, object>>();
//fill it here
var q = from a in myList Where a.Key.Equals("somevalue") Select a.Value
if(q.Count() > 0){ //you've got your value }

Die Art und Weise ich benutze, ist nur ein

Dictionary<string, List<string>>

Auf diese Weise haben Sie eine einzige Taste, um eine Liste von Strings zu halten.

Beispiel:

List<string> value = new List<string>();
if (dictionary.Contains(key)) {
     value = dictionary[key];
}
value.Add(newValue);

Sie meinen kongruent und nicht eine tatsächliche Duplikat? Andernfalls wird eine Hash-Tabelle würde arbeitet nicht in der Lage sein.

Congruent bedeutet, dass zwei getrennte Schlüssel für die Hash-Äquivalentwert kann, aber die Schlüssel nicht gleich sind.

Zum Beispiel: sagen, dass Ihre Hash-Tabelle der Hash-Funktion war nur hashval = Taste mod 3. Sowohl 1 und 4 Karte auf 1, sind aber unterschiedliche Werte. Hier wird Ihre Idee einer Liste ins Spiel kommt.

Wenn Sie 1 Nachschlag müssen, wird dieser Wert auf 1 gehasht wird die Liste durchlaufen, bis der Schlüssel = 1 gefunden wird.

Wenn Sie erlaubt für doppelte Schlüssel eingefügt werden, würden Sie nicht in der Lage sein, zu unterscheiden, welche Tasten Karte, auf die Werte.

stolperte ich über dieses Thema auf der Suche nach der gleichen Antwort, und fand keine, so manipulierten ich eine nackte Knochen Beispiel Lösung, die eine Liste der Wörterbücher up verwenden, das Überschreiben der Operator [] ein neues Wörterbuch zur Liste hinzuzufügen, wenn alle andere haben einen bestimmten Schlüssel (set), und eine Liste der Werte zurückgeben (get).
Es ist hässlich und ineffizient, es NUR bekommt / Sätze von Schlüsseln, und es gibt immer eine Liste, aber es funktioniert:

 class DKD {
        List<Dictionary<string, string>> dictionaries;
        public DKD(){
            dictionaries = new List<Dictionary<string, string>>();}
        public object this[string key]{
             get{
                string temp;
                List<string> valueList = new List<string>();
                for (int i = 0; i < dictionaries.Count; i++){
                    dictionaries[i].TryGetValue(key, out temp);
                    if (temp == key){
                        valueList.Add(temp);}}
                return valueList;}
            set{
                for (int i = 0; i < dictionaries.Count; i++){
                    if (dictionaries[i].ContainsKey(key)){
                        continue;}
                    else{
                        dictionaries[i].Add(key,(string) value);
                        return;}}
                dictionaries.Add(new Dictionary<string, string>());
                dictionaries.Last()[key] =(string)value;
            }
        }
    }

Ich ändere @Hector Correa ‚s Antwort in eine Erweiterung mit generischen Typen und auch eine benutzerdefinierte TryGetValue zu hinzugefügt werden.

  public static class ListWithDuplicateExtensions
  {
    public static void Add<TKey, TValue>(this List<KeyValuePair<TKey, TValue>> collection, TKey key, TValue value)
    {
      var element = new KeyValuePair<TKey, TValue>(key, value);
      collection.Add(element);
    }

    public static int TryGetValue<TKey, TValue>(this List<KeyValuePair<TKey, TValue>> collection, TKey key, out IEnumerable<TValue> values)
    {
      values = collection.Where(pair => pair.Key.Equals(key)).Select(pair => pair.Value);
      return values.Count();
    }
  }

Dies ist ein Abschleppwagen Weg Concurrent-Wörterbuch Ich denke, das wird Ihnen helfen:

public class HashMapDictionary<T1, T2> : System.Collections.IEnumerable
{
    private System.Collections.Concurrent.ConcurrentDictionary<T1, List<T2>> _keyValue = new System.Collections.Concurrent.ConcurrentDictionary<T1, List<T2>>();
    private System.Collections.Concurrent.ConcurrentDictionary<T2, List<T1>> _valueKey = new System.Collections.Concurrent.ConcurrentDictionary<T2, List<T1>>();

    public ICollection<T1> Keys
    {
        get
        {
            return _keyValue.Keys;
        }
    }

    public ICollection<T2> Values
    {
        get
        {
            return _valueKey.Keys;
        }
    }

    public int Count
    {
        get
        {
            return _keyValue.Count;
        }
    }

    public bool IsReadOnly
    {
        get
        {
            return false;
        }
    }

    public List<T2> this[T1 index]
    {
        get { return _keyValue[index]; }
        set { _keyValue[index] = value; }
    }

    public List<T1> this[T2 index]
    {
        get { return _valueKey[index]; }
        set { _valueKey[index] = value; }
    }

    public void Add(T1 key, T2 value)
    {
        lock (this)
        {
            if (!_keyValue.TryGetValue(key, out List<T2> result))
                _keyValue.TryAdd(key, new List<T2>() { value });
            else if (!result.Contains(value))
                result.Add(value);

            if (!_valueKey.TryGetValue(value, out List<T1> result2))
                _valueKey.TryAdd(value, new List<T1>() { key });
            else if (!result2.Contains(key))
                result2.Add(key);
        }
    }

    public bool TryGetValues(T1 key, out List<T2> value)
    {
        return _keyValue.TryGetValue(key, out value);
    }

    public bool TryGetKeys(T2 value, out List<T1> key)
    {
        return _valueKey.TryGetValue(value, out key);
    }

    public bool ContainsKey(T1 key)
    {
        return _keyValue.ContainsKey(key);
    }

    public bool ContainsValue(T2 value)
    {
        return _valueKey.ContainsKey(value);
    }

    public void Remove(T1 key)
    {
        lock (this)
        {
            if (_keyValue.TryRemove(key, out List<T2> values))
            {
                foreach (var item in values)
                {
                    var remove2 = _valueKey.TryRemove(item, out List<T1> keys);
                }
            }
        }
    }

    public void Remove(T2 value)
    {
        lock (this)
        {
            if (_valueKey.TryRemove(value, out List<T1> keys))
            {
                foreach (var item in keys)
                {
                    var remove2 = _keyValue.TryRemove(item, out List<T2> values);
                }
            }
        }
    }

    public void Clear()
    {
        _keyValue.Clear();
        _valueKey.Clear();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _keyValue.GetEnumerator();
    }
}

Beispiele:

public class TestA
{
    public int MyProperty { get; set; }
}

public class TestB
{
    public int MyProperty { get; set; }
}

            HashMapDictionary<TestA, TestB> hashMapDictionary = new HashMapDictionary<TestA, TestB>();

            var a = new TestA() { MyProperty = 9999 };
            var b = new TestB() { MyProperty = 60 };
            var b2 = new TestB() { MyProperty = 5 };
            hashMapDictionary.Add(a, b);
            hashMapDictionary.Add(a, b2);
            hashMapDictionary.TryGetValues(a, out List<TestB> result);
            foreach (var item in result)
            {
                //do something
            }

Ich benutze diese einfache Klasse:

public class ListMap<T,V> : List<KeyValuePair<T, V>>
{
    public void Add(T key, V value) {
        Add(new KeyValuePair<T, V>(key, value));
    }

    public List<V> Get(T key) {
        return FindAll(p => p.Key.Equals(key)).ConvertAll(p=> p.Value);
    }
}

Nutzung:

var fruits = new ListMap<int, string>();
fruits.Add(1, "apple");
fruits.Add(1, "orange");
var c = fruits.Get(1).Count; //c = 2;

U kann ein Verfahren zum Aufbau einer Verbindung String-Schlüssel definieren allenthalben u zu verwenden Wörterbuch wollen u müssen mit dieser Methode Ihr Schlüssel bauen zum Beispiel:

private string keyBuilder(int key1, int key2)
{
    return string.Format("{0}/{1}", key1, key2);
}

für die Verwendung:

myDict.ContainsKey(keyBuilder(key1, key2))

Doppelte Schlüssel brechen den gesamten Vertrag des Wörterbuchs. In einem Wörterbuch jeder Schlüssel ist einzigartig und auf einen einzigen Wert abgebildet. Wenn Sie ein Objekt auf eine beliebige Anzahl von zusätzlichen Objekten verknüpfen mögen, könnte die beste Wette so etwas wie einen Datensatz (im allgemeinen Sprachgebrauch eine Tabelle) sein. Setzen Sie Ihre Schlüssel in einer Spalte und Ihre Werte in der anderen. Dies ist deutlich langsamer als ein Wörterbuch, aber das ist Ihr Kompromiss für den Verlust der Fähigkeit, die wichtigsten Objekte Hash.

Auch das ist möglich:

Dictionary<string, string[]> previousAnswers = null;

Auf diese Weise können wir eindeutige Schlüssel haben. Hoffe, dass dies für Sie arbeitet.

Sie können dieselben Tasten mit verschiedenem Fall hinzufügen wie:

Schlüssel1
key1
KEY1
TASTE1
TASTE1
TASTE1

ich weiß, ist Dummy-Antwort, aber für mich gearbeitet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top