我正在寻找C#(2)中的通用双向1到1字典类,即.a BiDictionaryOneToOne
保证只包含每个值和键中的一个(无论如何最多为RefEquals),并且可以使用键或值进行搜索.有人知道,或者我应该自己实施吗?我不敢相信我是第一个需要这个的人......
在这个问题的答案中有一个BiDictionary ,但它不适用于唯一元素(并且也不实现RemoveByFirst(T t)或RemoveBySecond(S s)).
谢谢!
好的,这是我的尝试(建立在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(); } }
双向字典的更完整实现:
支持几乎所有原始接口Dictionary
(基础设施接口除外):
IDictionary
IReadOnlyDictionary
IDictionary
ICollection
(这一个及以下是上述基础接口)
ICollection
IReadOnlyCollection
IEnumerable
IEnumerable
序列化使用SerializableAttribute
.
使用DebuggerDisplayAttribute
(使用计数信息)和DebuggerTypeProxyAttribute
(用于在监视中显示键值对)调试视图.
反向字典作为IDictionary
属性提供,并且还实现上述所有接口.两个字典上的所有操作都会修改它们.
用法:
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); } }
您提到的问题也显示了此答案中的一对一实现.添加RemoveByFirst和RemoveBySecond将是微不足道的 - 正如实现额外的接口等.