>

C # (2)에서 일반적인 양방향 1 대 1 사전 클래스를 찾고 있습니다. BiDictionaryOneToOne<T, S>  각 값과 키 중 하나만 포함하도록 보장되며 (어쨌든 RefEquals까지) 키 또는 값을 사용하여 검색 할 수 있습니다. 누구나 하나를 알고 있거나 직접 구현해야합니까? 내가 이것을 필요로하는 첫 번째 사람이라고 믿을 수 없다 ...

이 질문이지만 고유 한 요소가 아니며 RemoveByFirst (T t) 또는 RemoveBySecond (S s)도 구현하지 않습니다.

감사합니다!


  • 답변 # 1

    여기, 나의 시도 (Jon 's를 기반으로 구축)는 여기에 보관되어 개선을 위해 열려 있습니다 :

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

  • 답변 # 2

    양방향 사전의보다 완전한 구현 :

    원래 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 (permalink, search)

    복사 :

    [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);
        }
    }
    
    

  • 답변 # 3

    도움이되는 질문은이 답변에서 일대일 구현을 보여줍니다. 추가 인터페이스 등을 구현하는 것처럼 RemoveByFirst 및 RemoveBySecond를 추가하는 것은 쉽지 않습니다.

  • 답변 # 4

    허용 된 답변과 동일하지만 Update 를 제공했습니다.  방법뿐만 아니라 조금 더 다듬어도됩니다 :

    public class BiDictionary<TKey1, TKey2> : IEnumerable<Tuple<TKey1, TKey2>>
    {
        Dictionary<TKey1, TKey2> _forwards;
        Dictionary<TKey2, TKey1> _reverses;
        public int Count
        {
            get
            {
                if (_forwards.Count != _reverses.Count)
                    throw new Exception("somewhere logic went wrong and your data got corrupt");
                return _forwards.Count;
            }
        }
        public ICollection<TKey1> Key1s
        {
            get { return _forwards.Keys; }
        }
        public ICollection<TKey2> Key2s
        {
            get { return _reverses.Keys; }
        }
        public BiDictionary(IEqualityComparer<TKey1> comparer1 = null, IEqualityComparer<TKey2> comparer2 = null)
        {
            _forwards = new Dictionary<TKey1, TKey2>(comparer1);
            _reverses = new Dictionary<TKey2, TKey1>(comparer2);
        }
    
        public bool ContainsKey1(TKey1 key)
        {
            return ContainsKey(key, _forwards);
        }
        private static bool ContainsKey<S, T>(S key, Dictionary<S, T> dict)
        {
            return dict.ContainsKey(key);
        }
        public bool ContainsKey2(TKey2 key)
        {
            return ContainsKey(key, _reverses);
        }
        public TKey2 GetValueByKey1(TKey1 key)
        {
            return GetValueByKey(key, _forwards);
        }
        private static T GetValueByKey<S, T>(S key, Dictionary<S, T> dict)
        {
            return dict[key];
        }
        public TKey1 GetValueByKey2(TKey2 key)
        {
            return GetValueByKey(key, _reverses);
        }
        public bool TryGetValueByKey1(TKey1 key, out TKey2 value)
        {
            return TryGetValue(key, _forwards, out value);
        }
        private static bool TryGetValue<S, T>(S key, Dictionary<S, T> dict, out T value)
        {
            return dict.TryGetValue(key, out value);
        }
        public bool TryGetValueByKey2(TKey2 key, out TKey1 value)
        {
            return TryGetValue(key, _reverses, out value);
        }
        public bool Add(TKey1 key1, TKey2 key2)
        {
            if (ContainsKey1(key1) || ContainsKey2(key2))   // very important
                return false;
            AddOrUpdate(key1, key2);
            return true;
        }
        public void AddOrUpdateByKey1(TKey1 key1, TKey2 key2)
        {
            if (!UpdateByKey1(key1, key2))
                AddOrUpdate(key1, key2);
        }
        // dont make this public; a dangerous method used cautiously in this class
        private void AddOrUpdate(TKey1 key1, TKey2 key2)
        {
            _forwards[key1] = key2;
            _reverses[key2] = key1;
        }
        public void AddOrUpdateKeyByKey2(TKey2 key2, TKey1 key1)
        {
            if (!UpdateByKey2(key2, key1))
                AddOrUpdate(key1, key2);
        }
        public bool UpdateKey1(TKey1 oldKey, TKey1 newKey)
        {
            return UpdateKey(oldKey, _forwards, newKey, (key1, key2) => AddOrUpdate(key1, key2));
        }
        private static bool UpdateKey<S, T>(S oldKey, Dictionary<S, T> dict, S newKey, Action<S, T> updater)
        {
            T otherKey;
            if (!TryGetValue(oldKey, dict, out otherKey) || ContainsKey(newKey, dict))
                return false;
            Remove(oldKey, dict);
            updater(newKey, otherKey);
            return true;
        }
        public bool UpdateKey2(TKey2 oldKey, TKey2 newKey)
        {
            return UpdateKey(oldKey, _reverses, newKey, (key1, key2) => AddOrUpdate(key2, key1));
        }
        public bool UpdateByKey1(TKey1 key1, TKey2 key2)
        {
            return UpdateByKey(key1, _forwards, _reverses, key2, (k1, k2) => AddOrUpdate(k1, k2));
        }
        private static bool UpdateByKey<S, T>(S key1, Dictionary<S, T> forwards, Dictionary<T, S> reverses, T key2,
                                              Action<S, T> updater)
        {
            T otherKey;
            if (!TryGetValue(key1, forwards, out otherKey) || ContainsKey(key2, reverses))
                return false;
            if (!Remove(otherKey, reverses))
                throw new Exception("somewhere logic went wrong and your data got corrupt");
            updater(key1, key2);
            return true;
        }
        public bool UpdateByKey2(TKey2 key2, TKey1 key1)
        {
            return UpdateByKey(key2, _reverses, _forwards, key1, (k1, k2) => AddOrUpdate(k2, k1));
        }
        public bool RemoveByKey1(TKey1 key)
        {
            return RemoveByKey(key, _forwards, _reverses);
        }
        private static bool RemoveByKey<S, T>(S key, Dictionary<S, T> keyDict, Dictionary<T, S> valueDict)
        {
            T otherKey;
            if (!TryGetValue(key, keyDict, out otherKey))
                return false;
            if (!Remove(key, keyDict) || !Remove(otherKey, 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, T> dict)
        {
            return dict.Remove(key);
        }
        public bool RemoveByKey2(TKey2 key)
        {
            return RemoveByKey(key, _reverses, _forwards);
        }
        public void Clear()
        {
            _forwards.Clear();
            _reverses.Clear();
        }
        public IEnumerator<Tuple<TKey1, TKey2>> GetEnumerator()
        {
            if (_forwards.Count != _reverses.Count)
                throw new Exception("somewhere logic went wrong and your data got corrupt");
            foreach (var item in _forwards)
                yield return Tuple.Create(item.Key, item.Value);
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    
    

    여기서 내 대답과 비슷합니다

    주의해야 할 사항 :

    <올>

    IEnumerable<> 만 구현했습니다. . 나는 ICollection<> 를 생각하지 않습니다  이 특별한 콜렉션 구조에 대해 메소드 이름이 모두 다를 수 있기 때문에 여기서 의미가 있습니다. IEnumerable<> 에 들어가야 할 것을 결정하는 것은 당신에게 달려 있습니다. . 이제

    와 같이 컬렉션 초기화 구문도 있습니다.
    var p = new BiDictionary<int, string> { 1, "a" }, { 2, "b" } };
    
    

    데이터 무결성을 위해 이상한 예외가 여기저기서 발생하려고했습니다. 내 코드에 버그가 있는지 알 수 있도록 더 안전한쪽에 있어야합니다.

    성능 : Value 를 검색 할 수 있습니다   Keys 중 하나와 이는 Get 를 의미합니다.  그리고 Contains  이 방법은 1 번만 조회하면됩니다 (O (1)). 와이즈 비즈  조회 2 회와 추가 2 회가 필요합니다. 와이즈 비즈  조회 1 회와 추가 2 회가 필요합니다. 와이즈 비즈  3 번 조회합니다. 모두 정답과 비슷합니다.

  • 답변 # 5

    C5 컬렉션 클래스를 사용하여 이러한 클래스를 만들었습니다.

    Add
    
    
    Update

  • 이전 php - PHP5에서 인라인 문자열 사용과 연결 속도 차이?
  • 다음 php - curl을 사용하여 큰 파일 다운로드