我正在寻找像词典< K,V>但保证它保留了订单。由于Dictionary是一个哈希表,我不认为它。
是否有针对此的通用集合,或者我是否需要使用旧的.NET 1.1集合之一?
答案 0 :(得分:24)
没有。但是,System.Collections.Specialized.OrderedDictionary应解决大部分需求。
编辑:另一个选择是将其转换为通用。我没有测试它,但它编译(C#6),应该工作。但是,它仍将具有与Ondrej Petrzilka在下面的评论中提到的相同的限制。
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);
}
答案 1 :(得分:13)
实际上有一个,它是通用的,自.net 2.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方法的文档:将对象添加到Collection的末尾。)。
答案 2 :(得分:8)
有一个OrderedDictionary类是一个字典,但可以按插入顺序编制索引,但它不是一般化的。目前.Net框架中没有一个普遍的。
我已经从.Net团队中的某个人那里读过一条评论,说明他们可能会在未来实施一个通用版本,但如果是这样的话,很可能会被称为IndexableDictionary
而不是OrderedDictionary
使其行为更加明显。
编辑:找到了报价。它位于OrderedDictionary
的MSDN页面上,归功于微软的David M. Kean:
这种类型实际上是错误的;它不是一个“有序”字典,而是一个“索引”字典。虽然,今天没有这种类型的等效通用版本,如果我们将来添加一个,我们可能会命名为'IndexedDictionary'类型。
答案 3 :(得分:5)
好吧,您可以使用List<KeyValuePair<K,V>>
,这将保留订单...但是您将失去字典的查找功能。为什么需要保留订单?
答案 4 :(得分:3)
code project上有一个通用的实现,它带有合理数量的测试用例。
作者选择了一个相当有趣的名字(KeyedList),这使得它很难找到。
答案 5 :(得分:3)
以下是非通用 IDictionary<TKey,TValue>
类型的包装。
此类型将以插入顺序返回键/值/对序列,就像Ruby 2.0哈希一样。
它不需要C#6魔法,符合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(); }
}
}
(这也意味着访问未分配的键会引发异常),并且应该是可序列化的。
它被命名为&#39; IndexedDictionary&#39;关于阿德里安的回答。
因人而异。
{{1}}
答案 6 :(得分:1)
我知道您正在编写C#,但Java有一个名为LinkedHashMap的类,它使用私有LinkedList来维护键的插入顺序。如果您找不到合适的通用解决方案,那么这可能是您实施自己的解决方案的开始。
答案 7 :(得分:1)
保留插入的通用键/值对的另一个选项是使用类似:
Queue<KeyValuePair<string, string>>
这将是一个有保障的有序列表。您可以在类似于添加/删除字典的有序派系中对队列进行排队和出列,而不是调整阵列大小。它通常可以作为非调整大小的有序(通过插入)数组和自动调整无序(通过插入)列表之间的中间地带。
答案 8 :(得分:1)
如果您需要Add
,Remove
,ContainsKey
和订单保留的持续复杂性,那么.NET Framework 4.5中没有这样的通用。
如果您对第三方代码感到满意,请查看我的存储库(允许的MIT许可证): https://github.com/OndrejPetrzilka/Rock.Collections
有OrderedDictionary<K,V>
集合:
Dictionary<K,V>
的源代码(来自.NET Core)Dictionary<K,V>
Add
相比,Remove
和Dictionary<K,V>
操作速度降低约20%答案 9 :(得分:-3)
代码:
//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