簡體   English   中英

具有唯一鍵和值的 C# 字典類型

[英]C# dictionary type with unique keys and values

我想知道 C# 中是否有類似於“字典”的內置類型,但 TKey 和 TValue 必須是唯一的。

例如::

d.Add(1, "1");
d.Add(2, "1"); // This would not be OK because "1" has already been used as a value.

我知道這有點奇怪,但似乎因為 BCL 中有大約 10 億個集合類型,所以它可能存在。 有任何想法嗎?

擁有 Dictionary 和 HashSet/secondary reverse Dictionary 怎么樣——它會解決這個問題,並且比檢查單個 Dictionary 表現更好。

像這樣的東西,包裝成類:

HashSet<string> secondary = new HashSet<string>(/*StringComparer.InvariantCultureIgnoreCase*/);
Dictionary<int, string>dictionary = new Dictionary<int, string>();
object syncer = new object();

public override void Add(int key, string value)
{
  lock(syncer)
  {
    if(dictionary.ContainsKey(key))
    {
      throw new Exception("Key already exists");
    }

    if(secondary.Add(value)
    {
      throw new Exception("Value already exists");
    }
    dictionary.Add(key, value);
  }
}

我通過將數據存儲為Dictionary<TKey, HashSet<TValue>>解決了這個問題。 如果你想要一個有 2 個主鍵的值,你可以用另一個字典替換 HashSet。

Dictionary<int, HashSet<int>> _myUniquePairOfIntegerKeys;
// OR
Dictionary<string, Dictionary<string, bool>> _myUniquePairOfStringKeysWithABooleanValue;

對於內部目的,我寫了一個BiDictionary 它不是防彈的,因為我沒有將它暴露給用戶,所以它對我來說很好用。 它允許我獲得我經常需要的任何一個密鑰。

KeyPair<,>是實現IEnumerable<,> KeyPair<,>所必需的,從而實現Add方法,以便我們可以使用對象初始值設定項。

internal class KeyPair<TKey1, TKey2>
{
    public TKey1 Key1 { get; set; }
    public TKey2 Key2 { get; set; }
}

這是作為動態對象的主類,以便我們在檢索值時可以在其上使用鍵名:

internal class BiDictionary<TKey1, TKey2> : DynamicObject, IEnumerable<KeyPair<TKey1, TKey2>>
{
    private readonly Dictionary<TKey1, TKey2> _K1K2 = new Dictionary<TKey1, TKey2>();
    private readonly Dictionary<TKey2, TKey1> _K2K1 = new Dictionary<TKey2, TKey1>();

    private readonly string _key1Name;
    private readonly string _key2Name;

    public BiDictionary(string key1Name, string key2Name)
    {
        _key1Name = key1Name;
        _key2Name = key2Name;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (binder.Name == _key1Name)
        {
            result = _K1K2;
            return true;
        }

        if (binder.Name == _key2Name)
        {
            result = _K2K1;
            return true;
        }

        result = null;
        return false;
    }

    public void Add(TKey1 key1, TKey2 key2)
    { 
        _K1K2.Add(key1, key2);
        _K2K1.Add(key2, key1);
    }

    public IEnumerator<KeyPair<TKey1, TKey2>> GetEnumerator()
    {
        return _K1K2.Zip(_K2K1, (d1, d2) => new KeyPair<TKey1, TKey2>
        {
            Key1 = d1.Key,
            Key2 = d2.Key
        }).GetEnumerator();
    }

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

例子:

dynamic bidic = new BiDictionary<string, string>("Key1", "Key2") 
{ 
    { "foo", "bar" }, 
    { "baz", "qux" } 
};
var bar = bidic.Key1["foo"];
var foo = bidic.Key2["bar"];

如果您修改任何外部詞典,它們可能會不同步。 為此,我使用ObservableDictionary以便我可以在一個更改時更新另一個,但為了簡單起見,我刪除了這部分代碼以演示主要邏輯。

有位於項目在這里,有一個類型是這樣的。 它被稱為 PairDictionary 並且運行良好。 不是最好的答案,但對於需要該自定義類的任何人。

您可以實現一個擴展方法,如果給定值已存在,則跳過添加到字典中。

static class Extensions
{
    public static void AddSafe(this Dictionary<int, string> dictionary, int key, string value)
    {
        if (!dictionary.ContainsValue(value))
            dictionary.Add(key, value);
    }
}

像普通函數一樣調用它

d.AddSafe(1, "1");
d.AddSafe(2, "1"); // This would not add anything

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM