C# 保留顺序的哈希集
我需要一个保留插入顺序的哈希集,框架中是否有这种实现?标准.NETC# 保留顺序的哈希集,c#,.net,hashset,C#,.net,Hashset,我需要一个保留插入顺序的哈希集,框架中是否有这种实现?标准.NET哈希集不保留插入顺序。 对于简单的测试,插入顺序可能会因为意外而保留,但不能保证,也不能总是这样。证明在两者之间进行一些删除就足够了 有关这方面的更多信息,请参见此问题: 我已经简单地实现了一个HashSet,它保证了插入顺序。它使用字典查找项目,并使用链接列表保持顺序。所有三个插入、删除和查找操作仍在O(1)中进行 公共类OrderedSet:ICollection { 专用只读词典; 私有只读链接列表Mu链接列表; 公共Ord
哈希集
不保留插入顺序。
对于简单的测试,插入顺序可能会因为意外而保留,但不能保证,也不能总是这样。证明在两者之间进行一些删除就足够了
有关这方面的更多信息,请参见此问题:
我已经简单地实现了一个HashSet
,它保证了插入顺序。它使用字典
查找项目,并使用链接列表
保持顺序。所有三个插入、删除和查找操作仍在O(1)中进行
公共类OrderedSet:ICollection
{
专用只读词典;
私有只读链接列表Mu链接列表;
公共OrderedSet()
:此(EqualityComparer.Default)
{
}
公共OrderedSet(IEqualityComparer比较程序)
{
m_Dictionary=新字典(比较器);
m_LinkedList=新建LinkedList();
}
public int Count=>m_Dictionary.Count;
公共虚拟bool IsReadOnly=>m_Dictionary.IsReadOnly;
作废ICollection.Add(T项)
{
增加(项目);
}
公共布尔添加(T项)
{
if(m_Dictionary.ContainsKey(item))返回false;
var node=m_LinkedList.AddLast(项目);
m_Dictionary.Add(项,节点);
返回true;
}
公共空间清除()
{
m_LinkedList.Clear();
m_Dictionary.Clear();
}
公共布尔删除(T项)
{
如果(item==null)返回false;
var found=m_Dictionary.TryGetValue(项,out var节点);
如果(!found)返回false;
m_字典。删除(项);
m_LinkedList.Remove(节点);
返回true;
}
公共IEnumerator GetEnumerator()
{
返回m_LinkedList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
公共布尔包含(T项)
{
返回项!=null&&m_Dictionary.ContainsKey(项);
}
public void CopyTo(T[]数组,int arrayIndex)
{
m_LinkedList.CopyTo(数组、数组索引);
}
}
通过为TKey和TItem指定相同的类型参数,可以轻松获得此功能:
public class OrderedHashSet<T> : KeyedCollection<T, T>
{
protected override T GetKeyForItem(T item)
{
return item;
}
}
公共类OrderedHashSet:KeyedCollection
{
受保护的覆盖T GetKeyForItem(T项)
{
退货项目;
}
}
如果您需要不断增加
添加
、删除
、包含
和订单保留的复杂性,那么.NET Framework 4.5中就没有这样的集合
如果您对第三方代码满意,请查看我的存储库(MIT许可证):
有OrderedHashSet
集合:
- 基于经典
源代码(来自.NET核心)HashSet
- 保留插入顺序并允许手动重新排序
- 功能反向枚举
- 具有与哈希集相同的操作复杂性
和Add
操作比Remove
慢20%HashSet
- 每项多消耗8字节内存
IEqualityComparer
传递给IDictionary
的相同重载。您的示例开箱即用,通过对象引用(至少对于类)检查相等性,并且不提供更改该行为的选项。然而,我明白这是一个简单的例子。@SimonBelanger同意。我刚刚发布了一个版本,在这里实现了常见构造函数和方法的所有变体:is'tm_LinkedList.Remove(node)代码>实际上是O(n)?@HimBromBeere-好问题。是的,但实际上不是。如果你想删除一个特定的元素,因为你必须找到这个元素,那么删除本身就是O(1)。如果你看一下我的实现,我们使用字典来查找它,它是O(1),而不是列表。首先,当你调用Remove
时,它会调用还是?第一个是O(n),第二个是O(1)。它调用Remove(TKey)
,因为它是最派生类上的一个。但是,当集合强制转换为集合或ICollection时调用Remove()将调用Remove(T)
重载。另一个说明是:Remove(T)
和Remove(TKey)
都是O(n)因为KeyedCollection
使用列表存储项目。请注意,与常规的System.Collections.Generic.HashSet
不同,这将在重复键上抛出System.ArgumentException
,而不是返回false
@kcnygaard-为什么您认为KeyedCollection保持插入顺序?在内部,它只是一本字典,它是。
public class OrderedHashSet<T> : KeyedCollection<T, T>
{
protected override T GetKeyForItem(T item)
{
return item;
}
}