当前位置:  开发笔记 > 编程语言 > 正文

C#中的双向1对1字典

如何解决《C#中的双向1对1字典》经验,为你挑选了3个好方法。

我正在寻找C#(2)中的通用双向1到1字典类,即.a BiDictionaryOneToOne保证只包含每个值和键中的一个(无论如何最多为RefEquals),并且可以使用键或值进行搜索.有人知道,或者我应该自己实施吗?我不敢相信我是第一个需要这个的人......

在这个问题的答案中有一个BiDictionary ,但它不适用于唯一元素(并且也不实现RemoveByFirst(T t)或RemoveBySecond(S s)).

谢谢!



1> Joel in Gö..:

好的,这是我的尝试(建立在Jon的 - 谢谢),存档在这里并开放改进:

/// 
/// This is a dictionary guaranteed to have only one of each value and key. 
/// It may be searched either by TFirst or by TSecond, giving a unique answer because it is 1 to 1.
/// 
/// The type of the "key"
/// The type of the "value"
public class BiDictionaryOneToOne
{
    IDictionary firstToSecond = new Dictionary();
    IDictionary secondToFirst = new Dictionary();

    #region Exception throwing methods

    /// 
    /// Tries to add the pair to the dictionary.
    /// Throws an exception if either element is already in the dictionary
    /// 
    /// 
    /// 
    public void Add(TFirst first, TSecond second)
    {
        if (firstToSecond.ContainsKey(first) || secondToFirst.ContainsKey(second))
            throw new ArgumentException("Duplicate first or second");

        firstToSecond.Add(first, second);
        secondToFirst.Add(second, first);
    }

    /// 
    /// Find the TSecond corresponding to the TFirst first
    /// Throws an exception if first is not in the dictionary.
    /// 
    /// the key to search for
    /// the value corresponding to first
    public TSecond GetByFirst(TFirst first)
    {
        TSecond second;
        if (!firstToSecond.TryGetValue(first, out second))
            throw new ArgumentException("first");

        return second; 
    }

    /// 
    /// Find the TFirst corresponing to the Second second.
    /// Throws an exception if second is not in the dictionary.
    /// 
    /// the key to search for
    /// the value corresponding to second
    public TFirst GetBySecond(TSecond second)
    {
        TFirst first;
        if (!secondToFirst.TryGetValue(second, out first))
            throw new ArgumentException("second");

        return first; 
    }


    /// 
    /// Remove the record containing first.
    /// If first is not in the dictionary, throws an Exception.
    /// 
    /// the key of the record to delete
    public void RemoveByFirst(TFirst first)
    {
        TSecond second;
        if (!firstToSecond.TryGetValue(first, out second))
            throw new ArgumentException("first");

        firstToSecond.Remove(first);
        secondToFirst.Remove(second);
    }

    /// 
    /// Remove the record containing second.
    /// If second is not in the dictionary, throws an Exception.
    /// 
    /// the key of the record to delete
    public void RemoveBySecond(TSecond second)
    {
        TFirst first;
        if (!secondToFirst.TryGetValue(second, out first))
            throw new ArgumentException("second");

        secondToFirst.Remove(second);
        firstToSecond.Remove(first);
    }

    #endregion

    #region Try methods

    /// 
    /// Tries to add the pair to the dictionary.
    /// Returns false if either element is already in the dictionary        
    /// 
    /// 
    /// 
    /// true if successfully added, false if either element are already in the dictionary
    public Boolean TryAdd(TFirst first, TSecond second)
    {
        if (firstToSecond.ContainsKey(first) || secondToFirst.ContainsKey(second))
            return false;

        firstToSecond.Add(first, second);
        secondToFirst.Add(second, first);
        return true;
    }


    /// 
    /// Find the TSecond corresponding to the TFirst first.
    /// Returns false if first is not in the dictionary.
    /// 
    /// the key to search for
    /// the corresponding value
    /// true if first is in the dictionary, false otherwise
    public Boolean TryGetByFirst(TFirst first, out TSecond second)
    {
        return firstToSecond.TryGetValue(first, out second);
    }

    /// 
    /// Find the TFirst corresponding to the TSecond second.
    /// Returns false if second is not in the dictionary.
    /// 
    /// the key to search for
    /// the corresponding value
    /// true if second is in the dictionary, false otherwise
    public Boolean TryGetBySecond(TSecond second, out TFirst first)
    {
        return secondToFirst.TryGetValue(second, out first);
    }

    /// 
    /// Remove the record containing first, if there is one.
    /// 
    /// 
    ///  If first is not in the dictionary, returns false, otherwise true
    public Boolean TryRemoveByFirst(TFirst first)
    {
        TSecond second;
        if (!firstToSecond.TryGetValue(first, out second))
            return false;

        firstToSecond.Remove(first);
        secondToFirst.Remove(second);
        return true;
    }

    /// 
    /// Remove the record containing second, if there is one.
    /// 
    /// 
    ///  If second is not in the dictionary, returns false, otherwise true
    public Boolean TryRemoveBySecond(TSecond second)
    {
        TFirst first;
        if (!secondToFirst.TryGetValue(second, out first))
            return false;

        secondToFirst.Remove(second);
        firstToSecond.Remove(first);
        return true;
    }

    #endregion        

    /// 
    /// The number of pairs stored in the dictionary
    /// 
    public Int32 Count
    {
        get { return firstToSecond.Count; }
    }

    /// 
    /// Removes all items from the dictionary.
    /// 
    public void Clear()
    {
        firstToSecond.Clear();
        secondToFirst.Clear();
    }
}


请上传到NuGet!

2> Athari..:

双向字典的更完整实现:

支持几乎所有原始接口Dictionary(基础设施接口除外):

IDictionary

IReadOnlyDictionary

IDictionary

ICollection> (这一个及以下是上述基础接口)

ICollection

IReadOnlyCollection>

IEnumerable>

IEnumerable

序列化使用SerializableAttribute.

使用DebuggerDisplayAttribute(使用计数信息)和DebuggerTypeProxyAttribute(用于在监视中显示键值对)调试视图.

反向字典作为IDictionary Reverse属性提供,并且还实现上述所有接口.两个字典上的所有操作都会修改它们.

用法:

var dic = new BiDictionary();
dic.Add(1, "1");
dic[2] = "2";
dic.Reverse.Add("3", 3);
dic.Reverse["4"] = 4;
dic.Clear();

代码可以在GitHub上的私有框架中找到:BiDictionary(TFirst,TSecond).cs(永久链接,搜索).

复制:

[Serializable]
[DebuggerDisplay ("Count = {Count}"), DebuggerTypeProxy (typeof(DictionaryDebugView<,>))]
public class BiDictionary : IDictionary, IReadOnlyDictionary, IDictionary
{
    private readonly IDictionary _firstToSecond = new Dictionary();
    [NonSerialized]
    private readonly IDictionary _secondToFirst = new Dictionary();
    [NonSerialized]
    private readonly ReverseDictionary _reverseDictionary;

    public BiDictionary ()
    {
        _reverseDictionary = new ReverseDictionary(this);
    }

    public IDictionary Reverse
    {
        get { return _reverseDictionary; }
    }

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

    object ICollection.SyncRoot
    {
        get { return ((ICollection)_firstToSecond).SyncRoot; }
    }

    bool ICollection.IsSynchronized
    {
        get { return ((ICollection)_firstToSecond).IsSynchronized; }
    }

    bool IDictionary.IsFixedSize
    {
        get { return ((IDictionary)_firstToSecond).IsFixedSize; }
    }

    public bool IsReadOnly
    {
        get { return _firstToSecond.IsReadOnly || _secondToFirst.IsReadOnly; }
    }

    public TSecond this [TFirst key]
    {
        get { return _firstToSecond[key]; }
        set
        {
            _firstToSecond[key] = value;
            _secondToFirst[value] = key;
        }
    }

    object IDictionary.this [object key]
    {
        get { return ((IDictionary)_firstToSecond)[key]; }
        set
        {
            ((IDictionary)_firstToSecond)[key] = value;
            ((IDictionary)_secondToFirst)[value] = key;
        }
    }

    public ICollection Keys
    {
        get { return _firstToSecond.Keys; }
    }

    ICollection IDictionary.Keys
    {
        get { return ((IDictionary)_firstToSecond).Keys; }
    }

    IEnumerable IReadOnlyDictionary.Keys
    {
        get { return ((IReadOnlyDictionary)_firstToSecond).Keys; }
    }

    public ICollection Values
    {
        get { return _firstToSecond.Values; }
    }

    ICollection IDictionary.Values
    {
        get { return ((IDictionary)_firstToSecond).Values; }
    }

    IEnumerable IReadOnlyDictionary.Values
    {
        get { return ((IReadOnlyDictionary)_firstToSecond).Values; }
    }

    public IEnumerator> GetEnumerator ()
    {
        return _firstToSecond.GetEnumerator();
    }

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

    IDictionaryEnumerator IDictionary.GetEnumerator ()
    {
        return ((IDictionary)_firstToSecond).GetEnumerator();
    }

    public void Add (TFirst key, TSecond value)
    {
        _firstToSecond.Add(key, value);
        _secondToFirst.Add(value, key);
    }

    void IDictionary.Add (object key, object value)
    {
        ((IDictionary)_firstToSecond).Add(key, value);
        ((IDictionary)_secondToFirst).Add(value, key);
    }

    public void Add (KeyValuePair item)
    {
        _firstToSecond.Add(item);
        _secondToFirst.Add(item.Reverse());
    }

    public bool ContainsKey (TFirst key)
    {
        return _firstToSecond.ContainsKey(key);
    }

    public bool Contains (KeyValuePair item)
    {
        return _firstToSecond.Contains(item);
    }

    public bool TryGetValue (TFirst key, out TSecond value)
    {
        return _firstToSecond.TryGetValue(key, out value);
    }

    public bool Remove (TFirst key)
    {
        TSecond value;
        if (_firstToSecond.TryGetValue(key, out value)) {
            _firstToSecond.Remove(key);
            _secondToFirst.Remove(value);
            return true;
        }
        else
            return false;
    }

    void IDictionary.Remove (object key)
    {
        var firstToSecond = (IDictionary)_firstToSecond;
        if (!firstToSecond.Contains(key))
            return;
        var value = firstToSecond[key];
        firstToSecond.Remove(key);
        ((IDictionary)_secondToFirst).Remove(value);
    }

    public bool Remove (KeyValuePair item)
    {
        return _firstToSecond.Remove(item);
    }

    public bool Contains (object key)
    {
        return ((IDictionary)_firstToSecond).Contains(key);
    }

    public void Clear ()
    {
        _firstToSecond.Clear();
        _secondToFirst.Clear();
    }

    public void CopyTo (KeyValuePair[] array, int arrayIndex)
    {
        _firstToSecond.CopyTo(array, arrayIndex);
    }

    void ICollection.CopyTo (Array array, int index)
    {
        ((IDictionary)_firstToSecond).CopyTo(array, index);
    }

    [OnDeserialized]
    internal void OnDeserialized (StreamingContext context)
    {
        _secondToFirst.Clear();
        foreach (var item in _firstToSecond)
            _secondToFirst.Add(item.Value, item.Key);
    }

    private class ReverseDictionary : IDictionary, IReadOnlyDictionary, IDictionary
    {
        private readonly BiDictionary _owner;

        public ReverseDictionary (BiDictionary owner)
        {
            _owner = owner;
        }

        public int Count
        {
            get { return _owner._secondToFirst.Count; }
        }

        object ICollection.SyncRoot
        {
            get { return ((ICollection)_owner._secondToFirst).SyncRoot; }
        }

        bool ICollection.IsSynchronized
        {
            get { return ((ICollection)_owner._secondToFirst).IsSynchronized; }
        }

        bool IDictionary.IsFixedSize
        {
            get { return ((IDictionary)_owner._secondToFirst).IsFixedSize; }
        }

        public bool IsReadOnly
        {
            get { return _owner._secondToFirst.IsReadOnly || _owner._firstToSecond.IsReadOnly; }
        }

        public TFirst this [TSecond key]
        {
            get { return _owner._secondToFirst[key]; }
            set
            {
                _owner._secondToFirst[key] = value;
                _owner._firstToSecond[value] = key;
            }
        }

        object IDictionary.this [object key]
        {
            get { return ((IDictionary)_owner._secondToFirst)[key]; }
            set
            {
                ((IDictionary)_owner._secondToFirst)[key] = value;
                ((IDictionary)_owner._firstToSecond)[value] = key;
            }
        }

        public ICollection Keys
        {
            get { return _owner._secondToFirst.Keys; }
        }

        ICollection IDictionary.Keys
        {
            get { return ((IDictionary)_owner._secondToFirst).Keys; }
        }

        IEnumerable IReadOnlyDictionary.Keys
        {
            get { return ((IReadOnlyDictionary)_owner._secondToFirst).Keys; }
        }

        public ICollection Values
        {
            get { return _owner._secondToFirst.Values; }
        }

        ICollection IDictionary.Values
        {
            get { return ((IDictionary)_owner._secondToFirst).Values; }
        }

        IEnumerable IReadOnlyDictionary.Values
        {
            get { return ((IReadOnlyDictionary)_owner._secondToFirst).Values; }
        }

        public IEnumerator> GetEnumerator ()
        {
            return _owner._secondToFirst.GetEnumerator();
        }

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

        IDictionaryEnumerator IDictionary.GetEnumerator ()
        {
            return ((IDictionary)_owner._secondToFirst).GetEnumerator();
        }

        public void Add (TSecond key, TFirst value)
        {
            _owner._secondToFirst.Add(key, value);
            _owner._firstToSecond.Add(value, key);
        }

        void IDictionary.Add (object key, object value)
        {
            ((IDictionary)_owner._secondToFirst).Add(key, value);
            ((IDictionary)_owner._firstToSecond).Add(value, key);
        }

        public void Add (KeyValuePair item)
        {
            _owner._secondToFirst.Add(item);
            _owner._firstToSecond.Add(item.Reverse());
        }

        public bool ContainsKey (TSecond key)
        {
            return _owner._secondToFirst.ContainsKey(key);
        }

        public bool Contains (KeyValuePair item)
        {
            return _owner._secondToFirst.Contains(item);
        }

        public bool TryGetValue (TSecond key, out TFirst value)
        {
            return _owner._secondToFirst.TryGetValue(key, out value);
        }

        public bool Remove (TSecond key)
        {
            TFirst value;
            if (_owner._secondToFirst.TryGetValue(key, out value)) {
                _owner._secondToFirst.Remove(key);
                _owner._firstToSecond.Remove(value);
                return true;
            }
            else
                return false;
        }

        void IDictionary.Remove (object key)
        {
            var firstToSecond = (IDictionary)_owner._secondToFirst;
            if (!firstToSecond.Contains(key))
                return;
            var value = firstToSecond[key];
            firstToSecond.Remove(key);
            ((IDictionary)_owner._firstToSecond).Remove(value);
        }

        public bool Remove (KeyValuePair item)
        {
            return _owner._secondToFirst.Remove(item);
        }

        public bool Contains (object key)
        {
            return ((IDictionary)_owner._secondToFirst).Contains(key);
        }

        public void Clear ()
        {
            _owner._secondToFirst.Clear();
            _owner._firstToSecond.Clear();
        }

        public void CopyTo (KeyValuePair[] array, int arrayIndex)
        {
            _owner._secondToFirst.CopyTo(array, arrayIndex);
        }

        void ICollection.CopyTo (Array array, int index)
        {
            ((IDictionary)_owner._secondToFirst).CopyTo(array, index);
        }
    }
}

internal class DictionaryDebugView
{
    private readonly IDictionary _dictionary;

    [DebuggerBrowsable (DebuggerBrowsableState.RootHidden)]
    public KeyValuePair[] Items
    {
        get
        {
            var array = new KeyValuePair[_dictionary.Count];
            _dictionary.CopyTo(array, 0);
            return array;
        }
    }

    public DictionaryDebugView (IDictionary dictionary)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");
        _dictionary = dictionary;
    }
}

public static class KeyValuePairExts
{
    public static KeyValuePair Reverse (this KeyValuePair @this)
    {
        return new KeyValuePair(@this.Value, @this.Key);
    }
}



3> Jon Skeet..:

您提到的问题也显示了此答案中的一对一实现.添加RemoveByFirst和RemoveBySecond将是微不足道的 - 正如实现额外的接口等.

推荐阅读
手机用户2502852037
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有