C#中的双向1对1词典
我正在寻找C#(2)中的泛型,双向1对1 Dictionary类,即。 一个BiDictionaryOneToOne<T, S>
,它保证只包含每个值和键中的一个(无论如何都是RefEquals),并且可以使用键或值进行搜索。 任何人都知道一个,或者我应该自己实现它? 我无法相信我是第一个需要这个的人...
在这个问题的答案中有一个BiDictionary,但它不是用于唯一元素(也不实现RemoveByFirst(T t)或RemoveBySecond(S s))。
谢谢!
好的,这里是我的尝试(建立在Jon的基础上 - 谢谢),在这里归档并开放改进:
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="TFirst">The type of the "key"</typeparam>
/// <typeparam name="TSecond">The type of the "value"</typeparam>
public class BiDictionaryOneToOne<TFirst, TSecond>
{
IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();
#region Exception throwing methods
/// <summary>
/// Tries to add the pair to the dictionary.
/// Throws an exception if either element is already in the dictionary
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
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);
}
/// <summary>
/// Find the TSecond corresponding to the TFirst first
/// Throws an exception if first is not in the dictionary.
/// </summary>
/// <param name="first">the key to search for</param>
/// <returns>the value corresponding to first</returns>
public TSecond GetByFirst(TFirst first)
{
TSecond second;
if (!firstToSecond.TryGetValue(first, out second))
throw new ArgumentException("first");
return second;
}
/// <summary>
/// Find the TFirst corresponing to the Second second.
/// Throws an exception if second is not in the dictionary.
/// </summary>
/// <param name="second">the key to search for</param>
/// <returns>the value corresponding to second</returns>
public TFirst GetBySecond(TSecond second)
{
TFirst first;
if (!secondToFirst.TryGetValue(second, out first))
throw new ArgumentException("second");
return first;
}
/// <summary>
/// Remove the record containing first.
/// If first is not in the dictionary, throws an Exception.
/// </summary>
/// <param name="first">the key of the record to delete</param>
public void RemoveByFirst(TFirst first)
{
TSecond second;
if (!firstToSecond.TryGetValue(first, out second))
throw new ArgumentException("first");
firstToSecond.Remove(first);
secondToFirst.Remove(second);
}
/// <summary>
/// Remove the record containing second.
/// If second is not in the dictionary, throws an Exception.
/// </summary>
/// <param name="second">the key of the record to delete</param>
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
/// <summary>
/// Tries to add the pair to the dictionary.
/// Returns false if either element is already in the dictionary
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns>true if successfully added, false if either element are already in the dictionary</returns>
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;
}
/// <summary>
/// Find the TSecond corresponding to the TFirst first.
/// Returns false if first is not in the dictionary.
/// </summary>
/// <param name="first">the key to search for</param>
/// <param name="second">the corresponding value</param>
/// <returns>true if first is in the dictionary, false otherwise</returns>
public Boolean TryGetByFirst(TFirst first, out TSecond second)
{
return firstToSecond.TryGetValue(first, out second);
}
/// <summary>
/// Find the TFirst corresponding to the TSecond second.
/// Returns false if second is not in the dictionary.
/// </summary>
/// <param name="second">the key to search for</param>
/// <param name="first">the corresponding value</param>
/// <returns>true if second is in the dictionary, false otherwise</returns>
public Boolean TryGetBySecond(TSecond second, out TFirst first)
{
return secondToFirst.TryGetValue(second, out first);
}
/// <summary>
/// Remove the record containing first, if there is one.
/// </summary>
/// <param name="first"></param>
/// <returns> If first is not in the dictionary, returns false, otherwise true</returns>
public Boolean TryRemoveByFirst(TFirst first)
{
TSecond second;
if (!firstToSecond.TryGetValue(first, out second))
return false;
firstToSecond.Remove(first);
secondToFirst.Remove(second);
return true;
}
/// <summary>
/// Remove the record containing second, if there is one.
/// </summary>
/// <param name="second"></param>
/// <returns> If second is not in the dictionary, returns false, otherwise true</returns>
public Boolean TryRemoveBySecond(TSecond second)
{
TFirst first;
if (!secondToFirst.TryGetValue(second, out first))
return false;
secondToFirst.Remove(second);
firstToSecond.Remove(first);
return true;
}
#endregion
/// <summary>
/// The number of pairs stored in the dictionary
/// </summary>
public Int32 Count
{
get { return firstToSecond.Count; }
}
/// <summary>
/// Removes all items from the dictionary.
/// </summary>
public void Clear()
{
firstToSecond.Clear();
secondToFirst.Clear();
}
}
双向字典的更完整实现:
Dictionary<TKey,TValue>
几乎所有接口 (基础设施接口除外): IDictionary<TKey, TValue>
IReadOnlyDictionary<TKey, TValue>
IDictionary
ICollection<KeyValuePair<TKey, TValue>>
(这个和下面是上面的基本接口) ICollection
IReadOnlyCollection<KeyValuePair<TKey, TValue>>
IEnumerable<KeyValuePair<TKey, TValue>>
IEnumerable
SerializableAttribute
。 DebuggerDisplayAttribute
(带有计数信息)和DebuggerTypeProxyAttribute
(用于在手表中显示键值对) 调试视图 。 IDictionary<TValue, TKey> Reverse
属性,也可以实现上面提到的所有接口。 对任何字典的所有操作都会修改两者。 用法:
var dic = new BiDictionary<int, string>();
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<TFirst, TSecond> : IDictionary<TFirst, TSecond>, IReadOnlyDictionary<TFirst, TSecond>, IDictionary
{
private readonly IDictionary<TFirst, TSecond> _firstToSecond = new Dictionary<TFirst, TSecond>();
[NonSerialized]
private readonly IDictionary<TSecond, TFirst> _secondToFirst = new Dictionary<TSecond, TFirst>();
[NonSerialized]
private readonly ReverseDictionary _reverseDictionary;
public BiDictionary ()
{
_reverseDictionary = new ReverseDictionary(this);
}
public IDictionary<TSecond, TFirst> 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<TFirst> Keys
{
get { return _firstToSecond.Keys; }
}
ICollection IDictionary.Keys
{
get { return ((IDictionary)_firstToSecond).Keys; }
}
IEnumerable<TFirst> IReadOnlyDictionary<TFirst, TSecond>.Keys
{
get { return ((IReadOnlyDictionary<TFirst, TSecond>)_firstToSecond).Keys; }
}
public ICollection<TSecond> Values
{
get { return _firstToSecond.Values; }
}
ICollection IDictionary.Values
{
get { return ((IDictionary)_firstToSecond).Values; }
}
IEnumerable<TSecond> IReadOnlyDictionary<TFirst, TSecond>.Values
{
get { return ((IReadOnlyDictionary<TFirst, TSecond>)_firstToSecond).Values; }
}
public IEnumerator<KeyValuePair<TFirst, TSecond>> 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<TFirst, TSecond> item)
{
_firstToSecond.Add(item);
_secondToFirst.Add(item.Reverse());
}
public bool ContainsKey (TFirst key)
{
return _firstToSecond.ContainsKey(key);
}
public bool Contains (KeyValuePair<TFirst, TSecond> 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<TFirst, TSecond> 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<TFirst, TSecond>[] 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<TSecond, TFirst>, IReadOnlyDictionary<TSecond, TFirst>, IDictionary
{
private readonly BiDictionary<TFirst, TSecond> _owner;
public ReverseDictionary (BiDictionary<TFirst, TSecond> 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<TSecond> Keys
{
get { return _owner._secondToFirst.Keys; }
}
ICollection IDictionary.Keys
{
get { return ((IDictionary)_owner._secondToFirst).Keys; }
}
IEnumerable<TSecond> IReadOnlyDictionary<TSecond, TFirst>.Keys
{
get { return ((IReadOnlyDictionary<TSecond, TFirst>)_owner._secondToFirst).Keys; }
}
public ICollection<TFirst> Values
{
get { return _owner._secondToFirst.Values; }
}
ICollection IDictionary.Values
{
get { return ((IDictionary)_owner._secondToFirst).Values; }
}
IEnumerable<TFirst> IReadOnlyDictionary<TSecond, TFirst>.Values
{
get { return ((IReadOnlyDictionary<TSecond, TFirst>)_owner._secondToFirst).Values; }
}
public IEnumerator<KeyValuePair<TSecond, TFirst>> 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<TSecond, TFirst> item)
{
_owner._secondToFirst.Add(item);
_owner._firstToSecond.Add(item.Reverse());
}
public bool ContainsKey (TSecond key)
{
return _owner._secondToFirst.ContainsKey(key);
}
public bool Contains (KeyValuePair<TSecond, TFirst> 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<TSecond, TFirst> 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<TSecond, TFirst>[] array, int arrayIndex)
{
_owner._secondToFirst.CopyTo(array, arrayIndex);
}
void ICollection.CopyTo (Array array, int index)
{
((IDictionary)_owner._secondToFirst).CopyTo(array, index);
}
}
}
internal class DictionaryDebugView<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> _dictionary;
[DebuggerBrowsable (DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Items
{
get
{
var array = new KeyValuePair<TKey, TValue>[_dictionary.Count];
_dictionary.CopyTo(array, 0);
return array;
}
}
public DictionaryDebugView (IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
}
public static class KeyValuePairExts
{
public static KeyValuePair<TValue, TKey> Reverse<TKey, TValue> (this KeyValuePair<TKey, TValue> @this)
{
return new KeyValuePair<TValue, TKey>(@this.Value, @this.Key);
}
}
您提到的问题也显示了此答案中的一对一实现。 添加RemoveByFirst和RemoveBySecond将是微不足道的 - 就像实现额外的接口等一样。
链接地址: http://www.djcxy.com/p/57837.html