c# - winforms tag property




Doppelte Schlüssel in.NET-Wörterbüchern? (15)

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.

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.


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

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.


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
            }

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

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 denke, etwas wie List<KeyValuePair<object, object>> würde den Job erledigen.


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


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.


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.


Sie können eine Methode zum Erstellen eines Compound-String-Schlüssels überall dort definieren, wo Sie das Dictionary verwenden möchten. Verwenden Sie diese Methode, um beispielsweise Ihren Schlüssel zu erstellen:

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

zum Benutzen:

myDict.ContainsKey(keyBuilder(key1, key2))


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 }







multimap