根据value来定位key在C#的Dictionary中如何实现?

来源:互联网 发布:域名注册是永久的吗 编辑:程序博客网 时间:2024/05/10 06:06

在C#中Dictionary就是hashtable,只是用起来有泛型更方便,它位于System.Collections.Generic,其定义为:

[SerializableAttribute][ComVisibleAttribute(false)]public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>,     ICollection<KeyValuePair<TKey, TValue>>,    IEnumerable<KeyValuePair<TKey, TValue>>,     IDictionary, ICollection, IEnumerable,    ISerializable, IDeserializationCallback

我们常常用key来得到value,例如:

string v = dict[key1];

如何用value来得到key? 例如:

string k = dict[value1];

这种需求是常见的,当然你可以遍历所有的value来定位key,或者用很炫的语法糖LINQ,像这样:

MyDict.FirstOrDefault(pair => pair.Value == "the value you want").Key;

但酱紫就不大约O(1)时间了。

一种做法是创建一个自定义的数据结构,里面用空间换时间,存储另外一个value,key的Dictionary,代码如下:

/// <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();    }}







0 0
原创粉丝点击