代码之家  ›  专栏  ›  技术社区  ›  FlySwat

保留插入顺序的通用键/值对集合?

  •  28
  • FlySwat  · 技术社区  · 16 年前

    是否有此通用集合,或者是否需要使用旧的.NET 1.1集合之一?

    10 回复  |  直到 16 年前
        1
  •  27
  •   McAden    9 年前

    没有。然而, System.Collections.Specialized.OrderedDictionary 应该解决最需要它的问题。

    编辑:另一个选项是将其转换为泛型。我还没有测试过它,但它可以编译(C#6),应该可以工作。然而,它仍然具有昂德雷杰·佩特齐尔卡在下面的评论中提到的相同限制。

        public class OrderdDictionary<T, K>
        {
            public OrderedDictionary UnderlyingCollection { get; } = new OrderedDictionary();
    
            public K this[T key]
            {
                get
                {
                    return (K)UnderlyingCollection[key];
                }
                set
                {
                    UnderlyingCollection[key] = value;
                }
            }
    
            public K this[int index]
            {
                get
                {
                    return (K)UnderlyingCollection[index];
                }
                set
                {
                    UnderlyingCollection[index] = value;
                }
            }
            public ICollection<T> Keys => UnderlyingCollection.Keys.OfType<T>().ToList();
            public ICollection<K> Values => UnderlyingCollection.Values.OfType<K>().ToList();
            public bool IsReadOnly => UnderlyingCollection.IsReadOnly;
            public int Count => UnderlyingCollection.Count;
            public IDictionaryEnumerator GetEnumerator() => UnderlyingCollection.GetEnumerator();
            public void Insert(int index, T key, K value) => UnderlyingCollection.Insert(index, key, value);
            public void RemoveAt(int index) => UnderlyingCollection.RemoveAt(index);
            public bool Contains(T key) => UnderlyingCollection.Contains(key);
            public void Add(T key, K value) => UnderlyingCollection.Add(key, value);
            public void Clear() => UnderlyingCollection.Clear();
            public void Remove(T key) => UnderlyingCollection.Remove(key);
            public void CopyTo(Array array, int index) => UnderlyingCollection.CopyTo(array, index);
        }
    
        2
  •  18
  •   Evgeniy Berezovsky    7 年前

    实际上有一个是通用的,从.NET2.0开始就存在了。它叫 KeyedCollection<TKey, TItem> . 但是,它有一个限制,即它根据值构造键 ,因此它不是通用的键/值对集合。(虽然你当然可以像这样使用它 KeyedCollection<TKey, Tuple<TKey, TItem>>

    IDictionary<TKey, TItem> .Dictionary

    我对它的一个小问题是它是一个抽象类,您必须对它进行子类化并实现:

    protected abstract TKey GetKeyForItem(TItem item)
    

    为此,我宁愿将lambda传递到构造函数中,但我想虚拟方法比lambda稍微快一点(对此的任何评论都值得赞赏)。

    编辑 正如评论中提到的问题: KeyedCollection 保留从继承的顺序 Collection<T> ,这是(它的来源) IList<T> . 另请参见Add方法的文档: ).

        3
  •  9
  •   adrianbanks    16 年前

    有一个 OrderedDictionary 类,该类是一个字典,但可以按插入顺序编制索引,但它不是泛型的。目前在.Net framework中没有一个通用的。

    我从.Net团队的某个地方读到一条评论,说他们 将来实现一个泛化版本,但如果是这样,它很可能会被调用 IndexableDictionary 而不是 OrderedDictionary 使其行为更加明显。

    编辑: 找到了报价单。它出现在MSDN页面上 有序词典

    这种类型实际上命名错误;它本身不是一个“有序”词典,而是一个“索引”词典。尽管目前还没有这种类型的等效泛型版本,但如果将来添加一个,我们很可能会将其命名为“IndexedDictionary”类型。

        4
  •  4
  •   user2864740 Heinzi    8 年前

    这是包装纸 非泛型 Systems.Collections.Specialized.OrderedDictionary 类型。

    插入顺序 ,非常类似于Ruby 2.0哈希。

    它不需要C#6魔法,符合 IDictionary<TKey,TValue> (这也意味着访问未分配的密钥会引发异常),并且应该是可序列化的。

    根据Adrian的答案,每个注释都将其命名为“IndexedDictionary”。

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    
    /// <summary>
    /// A dictionary that maintains insertion ordering of keys.
    /// 
    /// This is useful for emitting JSON where it is preferable to keep the key ordering
    /// for various human-friendlier reasons.
    /// 
    /// There is no support to manually re-order keys or to access keys
    /// by index without using Keys/Values or the Enumerator (eg).
    /// </summary>
    [Serializable]
    public sealed class IndexedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        // Non-generic version only in .NET 4.5
        private readonly OrderedDictionary _backing = new OrderedDictionary();
    
        private IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairs
        {
            get
            {
                return _backing.OfType<DictionaryEntry>()
                    .Select(e => new KeyValuePair<TKey, TValue>((TKey)e.Key, (TValue)e.Value));
            }
        }
    
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return KeyValuePairs.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            _backing[item.Key] = item.Value;
        }
    
        public void Clear()
        {
            _backing.Clear();
        }
    
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _backing.Contains(item.Key);
        }
    
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            KeyValuePairs.ToList().CopyTo(array, arrayIndex);
        }
    
        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            TValue value;
            if (TryGetValue(item.Key, out value)
                && Equals(value, item.Value))
            {
                Remove(item.Key);
                return true;
            }
            return false;
        }
    
        public int Count
        {
            get { return _backing.Count; }
        }
    
        public bool IsReadOnly
        {
            get { return _backing.IsReadOnly; }
        }
    
        public bool ContainsKey(TKey key)
        {
            return _backing.Contains(key);
        }
    
        public void Add(TKey key, TValue value)
        {
            _backing.Add(key, value);
        }
    
        public bool Remove(TKey key)
        {
            var result = _backing.Contains(key);
            if (result) {
                _backing.Remove(key);
            }
            return result;
        }
    
        public bool TryGetValue(TKey key, out TValue value)
        {
            object foundValue;
            if ((foundValue = _backing[key]) != null
                || _backing.Contains(key))
            {
                // Either found with a non-null value, or contained value is null.
                value = (TValue)foundValue;
                return true;
            }
            value = default(TValue);
            return false;
        }
    
        public TValue this[TKey key]
        {
            get
            {
                TValue value;
                if (TryGetValue(key, out value))
                    return value;
                throw new KeyNotFoundException();
            }
            set { _backing[key] = value; }
        }
    
        public ICollection<TKey> Keys
        {
            get { return _backing.Keys.OfType<TKey>().ToList(); }
        }
    
        public ICollection<TValue> Values
        {
            get { return _backing.Values.OfType<TValue>().ToList(); }
        }
    }
    
        5
  •  3
  •   Sam Saffron James Allen    16 年前

    上有一个通用实现 code project 它附带了合理数量的测试用例。

        6
  •  2
  •   John S.    11 年前

    保留插入的通用键/值对的另一个选项是使用以下内容:

    Queue<KeyValuePair<string, string>>
    

    这将是一个保证有序的列表。您可以按类似于添加/删除字典的顺序排队和出列,而不是调整数组的大小。它通常可以作为非调整大小有序(通过插入)数组和自动调整大小无序(通过插入)列表之间的中间地带。

        7
  •  1
  •   duffymo    16 年前

        8
  •  1
  •   Ondrej Petrzilka    9 年前

    如果你需要恒定的复杂度 Add Remove , ContainsKey 还有顺序保护,那么在.NETFramework4.5中就没有这样的通用版本了。

    如果您对第三方代码满意,请查看我的存储库(MIT许可证): https://github.com/OndrejPetrzilka/Rock.Collections

    OrderedDictionary<K,V> 收藏:

    • 源代码基于经典 Dictionary<K,V>
    • 保存 插入顺序 允许
    • 反向计数
    • 同样的操作复杂性 作为
    • 添加 去除 与其他设备相比,操作速度慢约20% 字典<K、 V>
        9
  •  -3
  •   Vamsi    13 年前

    //A SortedDictionary is sorted on the key (not value)
    System.Collections.Generic.SortedDictionary<string, string> testSortDic = new SortedDictionary<string, string>();
    
    //Add some values with the keys out of order
    testSortDic.Add("key5", "value 1");
    testSortDic.Add("key3", "value 2");
    testSortDic.Add("key2", "value 3");
    testSortDic.Add("key4", "value 4");
    testSortDic.Add("key1", "value 5"); 
    
    //Display the elements.  
    foreach (KeyValuePair<string, string> kvp in testSortDic)
    {
        Console.WriteLine("Key = {0}, value = {1}", kvp.Key, kvp.Value);
    }
    

    输出:

    Key = key1, value = value 5
    Key = key2, value = value 3
    Key = key3, value = value 2
    Key = key4, value = value 4
    Key = key5, value = value 1