c# using - Doppelte Schlüssel in.NET-Wörterbüchern?




tag winforms (19)

Gibt es in der .NET-Basisklassenbibliothek Wörterbuchklassen, in denen doppelte Schlüssel verwendet werden können? Die einzige Lösung, die ich gefunden habe, ist zum Beispiel eine Klasse zu erstellen wie:

Dictionary<string, List<object>>

Aber das ist ziemlich irritierend, um es tatsächlich zu benutzen. In Java glaube ich, dass eine MultiMap dies erreicht, aber in .NET kein Analog finden kann.


Answers

Dies ist ein 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
            }

Die List-Klasse funktioniert in der Regel ziemlich gut für Schlüssel / Wert-Sammlungen, die Duplikate enthalten, in denen Sie über die Sammlung iterieren möchten. 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);
}


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

EDIT: Sie erstellen in der Regel eine Enumerable.ToLookup mit Enumerable.ToLookup . Dies setzt voraus, dass Sie es später nicht ändern müssen - aber ich finde es normalerweise gut genug.

Wenn das bei dir nicht funktioniert, glaube ich nicht, dass es etwas im Framework gibt, das dir helfen wird - und das Wörterbuch so gut wie möglich zu benutzen :(


Ich stolperte über diesen Post auf der Suche nach der gleichen Antwort, und fand keine, also baute ich eine leere Beispiellösung mit einer Liste von Wörterbüchern auf und überschrieb den Operator [], um der Liste ein neues Wörterbuch hinzuzufügen, wenn alle anderen eine haben gegebener Schlüssel (set) und gibt eine Liste von Werten (get) zurück.
Es ist hässlich und ineffizient, es wird nur per Schlüssel abgerufen / gesetzt, und es gibt immer eine Liste zurück, 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;
            }
        }
    }

Es ist einfach genug, eine eigene Version eines Wörterbuchs zu "rollen", das "doppelte Schlüssel" -Einträge zulässt. Hier ist eine grobe einfache Implementierung. Sie sollten möglicherweise überlegen, Unterstützung für 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 benutzt:

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));
}

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


Die Art, wie ich benutze, ist nur ein

Dictionary<string, List<string>>

Auf diese Weise haben Sie einen einzigen Schlüssel, der eine Liste von Strings enthält.

Beispiel:

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

Wenn Sie> = .NET 4 verwenden, können Sie die 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());
}

Die NameValueCollection unterstützt mehrere Zeichenfolgenwerte unter einem Schlüssel (der auch eine Zeichenfolge ist), aber es ist das einzige Beispiel, das mir bekannt ist.

Ich tendiere dazu, ähnliche Konstrukte wie in Ihrem Beispiel zu erstellen, wenn ich auf Situationen stoße, in denen ich diese Art von Funktionalität brauche.


Auch das ist möglich:

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

Auf diese Weise können wir eindeutige Schlüssel haben. Hoffe das funktioniert für dich.


Sie können die gleichen Schlüssel mit verschiedenen Fällen hinzufügen, wie:

Schlüssel1
Schlüssel1
Schlüssel1
KeY1
kEy1
keY1

Ich weiß, ist Dummkopfantwort, aber arbeitete für mich.


Wenn Sie die Option List<KeyValuePair<string, object>> , können Sie LINQ für die Suche verwenden:

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 }

Ich bin gerade auf die PowerCollections Bibliothek gestoßen, die unter anderem eine Klasse namens MultiDictionary enthält. Dies umschließt diese Art von Funktionalität.



Meinst du kongruent und kein wirkliches Duplikat? Andernfalls könnte eine Hashtable nicht funktionieren.

Kongruent bedeutet, dass zwei separate Schlüssel auf den entsprechenden Wert synchronisiert werden können, die Schlüssel jedoch nicht gleich sind.

Zum Beispiel: Sagen Sie, dass die Hash-Funktion Ihrer Hashtabelle nur hashval = key mod 3 ist. Sowohl 1 als auch 4 werden auf 1 abgebildet, sind aber unterschiedliche Werte. Hier kommt Ihre Idee einer Liste ins Spiel.

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

Wenn Sie zulassen, dass doppelte Schlüssel eingefügt werden, können Sie nicht unterscheiden, welche Schlüssel welchen Werten zugeordnet sind.


Ich habe @Hector Correas Antwort in eine Erweiterung mit generischen Typen geändert und auch einen benutzerdefinierten TryGetValue hinzugefügt.

  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();
    }
  }

Hier ist eine Möglichkeit, dies mit List <KeyValuePair <string, string>> zu tun

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);
}

Ausgaben k1 = v1, k1 = v2, k1 = v3


Ich möchte Informationen über Python-Wörterbücher konsolidieren:

Ein leeres Wörterbuch erstellen

data = {}
# OR
data = dict()

Wörterbuch mit Anfangswerten erstellen

data = {'a':1,'b':2,'c':3}
# OR
data = dict(a=1, b=2, c=3)
# OR
data = {k: v for k, v in (('a', 1),('b',2),('c',3))}

Einzelnen Wert einfügen / aktualisieren

data['a']=1  # Updates if 'a' exists, else adds 'a'
# OR
data.update({'a':1})
# OR
data.update(dict(a=1))
# OR
data.update(a=1)

Mehrere Werte einfügen / aktualisieren

data.update({'c':3,'d':4})  # Updates 'c' and adds 'd'

Zusammengefügtes Wörterbuch erstellen, ohne die Originale zu ändern

data3 = {}
data3.update(data)  # Modifies data3, not data
data3.update(data2)  # Modifies data3, not data2

Elemente im Wörterbuch löschen

del data[key]  # Removes specific element in a dictionary
data.pop(key)  # Removes the key & returns the value
data.clear()  # Clears entire dictionary

Prüfen Sie, ob sich ein Schlüssel bereits im Wörterbuch befindet

key in data

Durchlaufen Sie Paare in einem Wörterbuch

for key in data: # Iterates just through the keys, ignoring the values
for key, value in d.items(): # Iterates through the pairs
for key in d.keys(): # Iterates just through key, ignoring the values
for value in d.values(): # Iterates just through value, ignoring the keys

Erstellen Sie ein Wörterbuch aus 2 Listen

data = dict(zip(list_with_keys, list_with_values))

Fühlen Sie sich frei, um mehr hinzuzufügen!





c# .net dictionary multimap