C#中的多键词典(另一种)?

C#中的多键词典(另一种)?,c#,data-structures,C#,Data Structures,在此基础上,是否有一个简单的解决方案来拥有一个多键字典,其中任何一个键都可以单独用于标识值 即 多键字典foo; foo.Add(键1、键2、值); myValue=foo[key1]; //value==myValue foo.移除(键2); myValue=foo[key1];//返回无效、异常或null 当然,这是一种面向对象语言,您可以实现任何您想要的O。您将需要解决一些不明确的问题(如果TKey1和TKey2是相同的类型,那么会调用哪些方法呢?似乎详细介绍了一个相当不错的实现 C语言的

在此基础上,是否有一个简单的解决方案来拥有一个多键字典,其中任何一个键都可以单独用于标识值

多键字典foo;
foo.Add(键1、键2、值);
myValue=foo[key1];
//value==myValue
foo.移除(键2);
myValue=foo[key1];//返回无效、异常或null

当然,这是一种面向对象语言,您可以实现任何您想要的O。您将需要解决一些不明确的问题(如果TKey1和TKey2是相同的类型,那么会调用哪些方法呢?

似乎详细介绍了一个相当不错的实现

C语言的多键通用字典类# MultiKeyDictionary是一个C#类 它包装并扩展了泛型 提供的字典对象 微软在.NET2.0及以上版本。这 允许开发人员创建泛型 价值观词典和参考文献 通过两个键而不是 只是微软提供的一个 通用规则的实施 字典。你可以看到我的 然而,关于CodeProject的文章(此处) 这段代码是最新的,有缺陷 免费的


目前.NET BCL中没有为这种类型的集合内置任何内容

我看到两种选择:

  • 使用两级词典。第一级将不同的键映射到某个公共唯一键(比如GUID),第二级将GUID映射到实际值

  • 创建一个自定义键类并实现Equals()和GetHashCode(),这样键的任何一个组件都足以找到整个键。然后,您可以提供助手方法,仅使用其中一个值来构造键的实例,以便进行查找


  • 是,定义一个类,该类使用两个键将对象添加到内部哈希表中

     public MyClass<k1, k2, T>: Dictionary<object, T>
      {
          private Dictionary<k1, k2> keyMap;
          public new Add(k1 key1Val, k2 key2Val, T object)
          {
             keyMap.Add(key1Val, key2Val);
             base.Add(k2, object)
          }
          public Remove(k1 key1Val) 
          { 
              base.Remove(keyMap[key1Val]); 
              keyMap.Remove(key1Val);
          }
          public Remove(k2 key2Val) 
          { 
            base.Remove(key2Val);
            keyMap.Remove(key2Val);
          }
      }
    
    公共MyClass:字典
    {
    专用字典键图;
    公共新添加(k1 key1Val、k2 key2Val、T对象)
    {
    添加(key1Val,key2Val);
    base.Add(k2,对象)
    }
    公共移除(k1键1VAL)
    { 
    base.Remove(keyMap[key1Val]);
    keyMap.Remove(key1Val);
    }
    公共移除(k2键2VAL)
    { 
    底座。移除(键2val);
    keyMap.Remove(key2Val);
    }
    }
    
    您将无法为这两种类型定义重载,并且泛型系统不允许任意数量的类型(如方法允许参数)。因此,您将被一组定义了2、3、4等同步键的类所困扰。此外,还必须使用对象作为get和set的参数,使用运行时类型检查来模拟重载

    此外,您只存储一个
    字典,其他字典将是
    ,并将作为主字典的索引

    它主要是锅炉板代码。

    您可能会发现我的实现是将其从Java重写为C#的良好基础。编程模型没有我喜欢的那么优雅,但它并不适合直接使用进行开发。相反,它位于一个缓存库后面,该库提供标准注释,以允许简洁的编码风格。通过使用Map接口,当它与自填充、过期和可收回的Map装饰器组合时,它提供了一个干净的组合模型。我相信有人会想出一个很好的编程接口,在可以接受的情况下,可以直接使用它来失去Map接口的好处。

    另一个简单(有效)的实现是使用“
    Pair
    类型作为字典键,比如

    Dictionary<Pair<TKey1, TKey2>, TValue> foo;
    foo.Add(new Pair<TKey1, TKey2>(key1, key2), value);
    
    字典foo;
    foo.Add(新对(键1,键2),值);
    
    Pair一致地实现了
    Equals
    GetHashCode
    ,因此您不需要求助于多级字典(它们更麻烦,可能也不太有效)


    如果你需要三键词典,还有一个
    三键词典。

    我试过了,效果很好(包括添加、删除和索引器)

    公共类多键字典:字典
    {
    公共V本[K1 index1,K2 index2]
    {
    得到
    {
    返回此[新的KeyValuePair(index1,index2)];
    }
    设置
    {
    此[新的KeyValuePair(index1,index2)]=值;
    }
    }
    公共布尔删除(K1 index1,K2 index2)
    {
    返回base.Remove(新的KeyValuePair(index1,index2));
    }
    公共无效添加(K1 index1,K2 index2,V值)
    {
    添加(新的KeyValuePair(index1,index2),value);
    }
    }
    
    甚至我把它扩展到了4个值:

    public class MultikeyDictionary<K1, K2, K3, V> : MultikeyDictionary<KeyValuePair<K1, K2>, K3, V>
    {
        public V this[K1 index1, K2 index2, K3 index3]
        {
            get
            {
                return base[new KeyValuePair<K1, K2>(index1, index2), index3];
            }
            set
            {
                base[new KeyValuePair<K1, K2>(index1, index2), index3] = value;
            }
        }
    
        public bool Remove(K1 index1, K2 index2, K3 index3)
        {
            return base.Remove(new KeyValuePair<K1, K2>(index1, index2), index3);
        }
    
        public void Add(K1 index1, K2 index2, K3 index3, V value)
        {
            base.Add(new KeyValuePair<K1, K2>(index1, index2), index3, value);
        }
    }
    
    公共类MultikeyDictionary:MultikeyDictionary
    {
    公共V本[K1 index1,K2 index2,K3 index3]
    {
    得到
    {
    返回基[newkeyvaluepair(index1,index2),index3];
    }
    设置
    {
    基[新的键值对(index1,index2),index3]=值;
    }
    }
    公共布尔删除(K1 index1、K2 index2、K3 index3)
    {
    返回基。移除(新的KeyValuePair(index1、index2、index3);
    }
    公共无效添加(K1 index1、K2 index2、K3 index3、V值)
    {
    添加(新的KeyValuePair(index1,index2),index3,value);
    }
    }
    
    享受


    我发现这里的许多答案都不必要地复杂、性能较差或根本无法使用。最好的方法是将副键的
    KeyValuePair
    和值作为任一词典的
    value
    组合在一起。这使您只需对删除和更新操作进行一次查找。一个简单的实现:

    public class DualDictionary<TKey1, TKey2, TValue> : IEnumerable<KeyValuePair<Tuple<TKey1, TKey2>, TValue>>
    {
        Dictionary<TKey1, KeyValuePair<TKey2, TValue>> _firstKeys;
        Dictionary<TKey2, KeyValuePair<TKey1, TValue>> _secondKeys;
    
        public int Count
        {
            get
            {
                if (_firstKeys.Count != _secondKeys.Count)
                    throw new Exception("somewhere logic went wrong and your data got corrupt");
    
                return _firstKeys.Count;
            }
        }
    
        public ICollection<TKey1> Key1s
        {
            get { return _firstKeys.Keys; }
        }
    
        public ICollection<TKey2> Key2s
        {
            get { return _secondKeys.Keys; }
        }
    
        public IEnumerable<TValue> Values
        {
            get { return this.Select(kvp => kvp.Value); }
        }
    
        public DualDictionary(IEqualityComparer<TKey1> comparer1 = null, IEqualityComparer<TKey2> comparer2 = null)
        {
            _firstKeys = new Dictionary<TKey1, KeyValuePair<TKey2, TValue>>(comparer1);
            _secondKeys = new Dictionary<TKey2, KeyValuePair<TKey1, TValue>>(comparer2);
        }
    
    
    
        public bool ContainsKey1(TKey1 key)
        {
            return ContainsKey(key, _firstKeys);
        }
    
        private static bool ContainsKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict)
        {
            return dict.ContainsKey(key);
        }
    
        public bool ContainsKey2(TKey2 key)
        {
            return ContainsKey(key, _secondKeys);
        }
    
        public TValue GetValueByKey1(TKey1 key)
        {
            return GetValueByKey(key, _firstKeys);
        }
    
        private static TValue GetValueByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict)
        {
            return dict[key].Value;
        }
    
        public TValue GetValueByKey2(TKey2 key)
        {
            return GetValueByKey(key, _secondKeys);
        }
    
        public bool TryGetValueByKey1(TKey1 key, out TValue value)
        {
            return TryGetValueByKey(key, _firstKeys, out value);
        }
    
        private static bool TryGetValueByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict, out TValue value)
        {
            KeyValuePair<T, TValue> otherPairing;
            bool b = TryGetValue(key, dict, out otherPairing);
            value = otherPairing.Value;
            return b;
        }
    
        private static bool TryGetValue<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict,
                                              out KeyValuePair<T, TValue> otherPairing)
        {
            return dict.TryGetValue(key, out otherPairing);
        }
    
        public bool TryGetValueByKey2(TKey2 key, out TValue value)
        {
            return TryGetValueByKey(key, _secondKeys, out value);
        }
    
        public bool Add(TKey1 key1, TKey2 key2, TValue value)
        {
            if (ContainsKey1(key1) || ContainsKey2(key2))   // very important
                return false;
    
            AddOrUpdate(key1, key2, value);
            return true;
        }
    
        // dont make this public; a dangerous method used cautiously in this class
        private void AddOrUpdate(TKey1 key1, TKey2 key2, TValue value)
        {
            _firstKeys[key1] = new KeyValuePair<TKey2, TValue>(key2, value);
            _secondKeys[key2] = new KeyValuePair<TKey1, TValue>(key1, value);
        }
    
        public bool UpdateKey1(TKey1 oldKey, TKey1 newKey)
        {
            return UpdateKey(oldKey, _firstKeys, newKey, (key1, key2, value) => AddOrUpdate(key1, key2, value));
        }
    
        private static bool UpdateKey<S, T>(S oldKey, Dictionary<S, KeyValuePair<T, TValue>> dict, S newKey,
                                            Action<S, T, TValue> updater)
        {
            KeyValuePair<T, TValue> otherPairing;
            if (!TryGetValue(oldKey, dict, out otherPairing) || ContainsKey(newKey, dict))
                return false;
    
            Remove(oldKey, dict);
            updater(newKey, otherPairing.Key, otherPairing.Value);
            return true;
        }
    
        public bool UpdateKey2(TKey2 oldKey, TKey2 newKey)
        {
            return UpdateKey(oldKey, _secondKeys, newKey, (key1, key2, value) => AddOrUpdate(key2, key1, value));
        }
    
        public bool UpdateByKey1(TKey1 key, TValue value)
        {
            return UpdateByKey(key, _firstKeys, (key1, key2) => AddOrUpdate(key1, key2, value));
        }
    
        private static bool UpdateByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict, Action<S, T> updater)
        {
            KeyValuePair<T, TValue> otherPairing;
            if (!TryGetValue(key, dict, out otherPairing))
                return false;
    
            updater(key, otherPairing.Key);
            return true;
        }
    
        public bool UpdateByKey2(TKey2 key, TValue value)
        {
            return UpdateByKey(key, _secondKeys, (key1, key2) => AddOrUpdate(key2, key1, value));
        }
    
        public bool RemoveByKey1(TKey1 key)
        {
            return RemoveByKey(key, _firstKeys, _secondKeys);
        }
    
        private static bool RemoveByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> keyDict,
                                              Dictionary<T, KeyValuePair<S, TValue>> valueDict)
        {
            KeyValuePair<T, TValue> otherPairing;
            if (!TryGetValue(key, keyDict, out otherPairing))
                return false;
    
            if (!Remove(key, keyDict) || !Remove(otherPairing.Key, valueDict))
                throw new Exception("somewhere logic went wrong and your data got corrupt");
    
            return true;
        }
    
        private static bool Remove<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict)
        {
            return dict.Remove(key);
        }
    
        public bool RemoveByKey2(TKey2 key)
        {
            return RemoveByKey(key, _secondKeys, _firstKeys);
        }
    
        public void Clear()
        {
            _firstKeys.Clear();
            _secondKeys.Clear();
        }
    
        public IEnumerator<KeyValuePair<Tuple<TKey1, TKey2>, TValue>> GetEnumerator()
        {
            if (_firstKeys.Count != _secondKeys.Count)
                throw new Exception("somewhere logic went wrong and your data got corrupt");
    
            return _firstKeys.Select(kvp => new KeyValuePair<Tuple<TKey1, TKey2>, TValue>(Tuple.Create(kvp.Key, kvp.Value.Key),
                                                                                          kvp.Value.Value)).GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    
    公共类双字典:IEnumerable
    {
    字典第一键;
    字典(附键),;
    公共整数计数
    {
    得到
    {
    如果(_firstKeys.Count!=_secondKeys.Count)
    抛出新异常(“某个地方逻辑出错,数据损坏”);
    返回_firstKeys.Count;
    }
    }
    公共I
    
    public class MultikeyDictionary<K1, K2, K3, V> : MultikeyDictionary<KeyValuePair<K1, K2>, K3, V>
    {
        public V this[K1 index1, K2 index2, K3 index3]
        {
            get
            {
                return base[new KeyValuePair<K1, K2>(index1, index2), index3];
            }
            set
            {
                base[new KeyValuePair<K1, K2>(index1, index2), index3] = value;
            }
        }
    
        public bool Remove(K1 index1, K2 index2, K3 index3)
        {
            return base.Remove(new KeyValuePair<K1, K2>(index1, index2), index3);
        }
    
        public void Add(K1 index1, K2 index2, K3 index3, V value)
        {
            base.Add(new KeyValuePair<K1, K2>(index1, index2), index3, value);
        }
    }
    
    public class DualDictionary<TKey1, TKey2, TValue> : IEnumerable<KeyValuePair<Tuple<TKey1, TKey2>, TValue>>
    {
        Dictionary<TKey1, KeyValuePair<TKey2, TValue>> _firstKeys;
        Dictionary<TKey2, KeyValuePair<TKey1, TValue>> _secondKeys;
    
        public int Count
        {
            get
            {
                if (_firstKeys.Count != _secondKeys.Count)
                    throw new Exception("somewhere logic went wrong and your data got corrupt");
    
                return _firstKeys.Count;
            }
        }
    
        public ICollection<TKey1> Key1s
        {
            get { return _firstKeys.Keys; }
        }
    
        public ICollection<TKey2> Key2s
        {
            get { return _secondKeys.Keys; }
        }
    
        public IEnumerable<TValue> Values
        {
            get { return this.Select(kvp => kvp.Value); }
        }
    
        public DualDictionary(IEqualityComparer<TKey1> comparer1 = null, IEqualityComparer<TKey2> comparer2 = null)
        {
            _firstKeys = new Dictionary<TKey1, KeyValuePair<TKey2, TValue>>(comparer1);
            _secondKeys = new Dictionary<TKey2, KeyValuePair<TKey1, TValue>>(comparer2);
        }
    
    
    
        public bool ContainsKey1(TKey1 key)
        {
            return ContainsKey(key, _firstKeys);
        }
    
        private static bool ContainsKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict)
        {
            return dict.ContainsKey(key);
        }
    
        public bool ContainsKey2(TKey2 key)
        {
            return ContainsKey(key, _secondKeys);
        }
    
        public TValue GetValueByKey1(TKey1 key)
        {
            return GetValueByKey(key, _firstKeys);
        }
    
        private static TValue GetValueByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict)
        {
            return dict[key].Value;
        }
    
        public TValue GetValueByKey2(TKey2 key)
        {
            return GetValueByKey(key, _secondKeys);
        }
    
        public bool TryGetValueByKey1(TKey1 key, out TValue value)
        {
            return TryGetValueByKey(key, _firstKeys, out value);
        }
    
        private static bool TryGetValueByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict, out TValue value)
        {
            KeyValuePair<T, TValue> otherPairing;
            bool b = TryGetValue(key, dict, out otherPairing);
            value = otherPairing.Value;
            return b;
        }
    
        private static bool TryGetValue<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict,
                                              out KeyValuePair<T, TValue> otherPairing)
        {
            return dict.TryGetValue(key, out otherPairing);
        }
    
        public bool TryGetValueByKey2(TKey2 key, out TValue value)
        {
            return TryGetValueByKey(key, _secondKeys, out value);
        }
    
        public bool Add(TKey1 key1, TKey2 key2, TValue value)
        {
            if (ContainsKey1(key1) || ContainsKey2(key2))   // very important
                return false;
    
            AddOrUpdate(key1, key2, value);
            return true;
        }
    
        // dont make this public; a dangerous method used cautiously in this class
        private void AddOrUpdate(TKey1 key1, TKey2 key2, TValue value)
        {
            _firstKeys[key1] = new KeyValuePair<TKey2, TValue>(key2, value);
            _secondKeys[key2] = new KeyValuePair<TKey1, TValue>(key1, value);
        }
    
        public bool UpdateKey1(TKey1 oldKey, TKey1 newKey)
        {
            return UpdateKey(oldKey, _firstKeys, newKey, (key1, key2, value) => AddOrUpdate(key1, key2, value));
        }
    
        private static bool UpdateKey<S, T>(S oldKey, Dictionary<S, KeyValuePair<T, TValue>> dict, S newKey,
                                            Action<S, T, TValue> updater)
        {
            KeyValuePair<T, TValue> otherPairing;
            if (!TryGetValue(oldKey, dict, out otherPairing) || ContainsKey(newKey, dict))
                return false;
    
            Remove(oldKey, dict);
            updater(newKey, otherPairing.Key, otherPairing.Value);
            return true;
        }
    
        public bool UpdateKey2(TKey2 oldKey, TKey2 newKey)
        {
            return UpdateKey(oldKey, _secondKeys, newKey, (key1, key2, value) => AddOrUpdate(key2, key1, value));
        }
    
        public bool UpdateByKey1(TKey1 key, TValue value)
        {
            return UpdateByKey(key, _firstKeys, (key1, key2) => AddOrUpdate(key1, key2, value));
        }
    
        private static bool UpdateByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict, Action<S, T> updater)
        {
            KeyValuePair<T, TValue> otherPairing;
            if (!TryGetValue(key, dict, out otherPairing))
                return false;
    
            updater(key, otherPairing.Key);
            return true;
        }
    
        public bool UpdateByKey2(TKey2 key, TValue value)
        {
            return UpdateByKey(key, _secondKeys, (key1, key2) => AddOrUpdate(key2, key1, value));
        }
    
        public bool RemoveByKey1(TKey1 key)
        {
            return RemoveByKey(key, _firstKeys, _secondKeys);
        }
    
        private static bool RemoveByKey<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> keyDict,
                                              Dictionary<T, KeyValuePair<S, TValue>> valueDict)
        {
            KeyValuePair<T, TValue> otherPairing;
            if (!TryGetValue(key, keyDict, out otherPairing))
                return false;
    
            if (!Remove(key, keyDict) || !Remove(otherPairing.Key, valueDict))
                throw new Exception("somewhere logic went wrong and your data got corrupt");
    
            return true;
        }
    
        private static bool Remove<S, T>(S key, Dictionary<S, KeyValuePair<T, TValue>> dict)
        {
            return dict.Remove(key);
        }
    
        public bool RemoveByKey2(TKey2 key)
        {
            return RemoveByKey(key, _secondKeys, _firstKeys);
        }
    
        public void Clear()
        {
            _firstKeys.Clear();
            _secondKeys.Clear();
        }
    
        public IEnumerator<KeyValuePair<Tuple<TKey1, TKey2>, TValue>> GetEnumerator()
        {
            if (_firstKeys.Count != _secondKeys.Count)
                throw new Exception("somewhere logic went wrong and your data got corrupt");
    
            return _firstKeys.Select(kvp => new KeyValuePair<Tuple<TKey1, TKey2>, TValue>(Tuple.Create(kvp.Key, kvp.Value.Key),
                                                                                          kvp.Value.Value)).GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    
    Dictionary<Guid, Object> objs = new Dictionary<Guid, Object>();
    Dictionary<int, Guid> guids = new Dictionary<int, Guid>();
    
    private void Set(object sender, Object obj)
    {
        objs[obj.Guid] = obj;
        guids[obj.Id] = obj.Guid;
    }
    
    public Object Get(int id)
    {
        return guids.ContainsKey(id) ? Get(guids[id]) : null;
    }
    
    public Object Get(Guid guid)
    {
        return objs.ContainsKey(guid) ? objs[guid] : null;
    }