保留排序的HashSet

Sam*_*ron 45 .net c# hashset

我需要一个保留插入排序的HashSet,在框架中是否有任何实现?

Geo*_*dze 28

标准.NET HashSet不保留插入顺序. 对于简单的测试,插入顺序可能由于事故而保留,但是不能保证并且不会总是以这种方式工作.为了证明在两者之间进行一些删除就足够了.

有关详细信息,请参阅此问题:HashSet是否保留了插入顺序?

我简要地实现了一个HashSet保证插入顺序的方法.它使用Dictionary查找项目和LinkedList保存顺序.所有三个插入,移除和查找工作仍在O(1)中.

public class OrderedSet<T> : ICollection<T>
{
    private readonly IDictionary<T, LinkedListNode<T>> m_Dictionary;
    private readonly LinkedList<T> m_LinkedList;

    public OrderedSet()
        : this(EqualityComparer<T>.Default)
    {
    }

    public OrderedSet(IEqualityComparer<T> comparer)
    {
        m_Dictionary = new Dictionary<T, LinkedListNode<T>>(comparer);
        m_LinkedList = new LinkedList<T>();
    }

    public int Count
    {
        get { return m_Dictionary.Count; }
    }

    public virtual bool IsReadOnly
    {
        get { return m_Dictionary.IsReadOnly; }
    }

    void ICollection<T>.Add(T item)
    {
        Add(item);
    }

    public bool Add(T item)
    {
        if (m_Dictionary.ContainsKey(item)) return false;
        LinkedListNode<T> node = m_LinkedList.AddLast(item);
        m_Dictionary.Add(item, node);
        return true;
    }

    public void Clear()
    {
        m_LinkedList.Clear();
        m_Dictionary.Clear();
    }

    public bool Remove(T item)
    {
        LinkedListNode<T> node;
        bool found = m_Dictionary.TryGetValue(item, out node);
        if (!found) return false;
        m_Dictionary.Remove(item);
        m_LinkedList.Remove(node);
        return true;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return m_LinkedList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public bool Contains(T item)
    {
        return m_Dictionary.ContainsKey(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        m_LinkedList.CopyTo(array, arrayIndex);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您应该提供一个重载,将"IEqualityComparer <T>"传递给`IDictionary <T>`的相同重载.开箱即用,您的示例通过对象引用(至少对类)检查相等性,并且不提供更改该行为的选项.但我明白这是一个简单的例子. (3认同)

kcn*_*ard 19

您可以使用KeyedCollection<TKey,TItem>为TKey和TItem指定相同的类型参数来轻松获得此功能:

public class OrderedHashSet<T> : KeyedCollection<T, T>
{
    protected override T GetKeyForItem(T item)
    {
        return item;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 另一个澄清:"Remove(T)"和"Remove(TKey)"都是O(n),因为`KeyedCollection <T,T>`使用一个列表来存储项目. (4认同)
  • 当调用`Remove`将它调用[`删除(T)`](http://msdn.microsoft.com/en-us/library/ms132413(V = vs.110)的.aspx)或[`删除( TKEY的)`](http://msdn.microsoft.com/en-us/library/ms132459(v = vs.110)的.aspx)?第一个是O(n),第二个是O(1). (3认同)
  • 请注意,与常规的`System.Collections.Generic.HashSet <T>`不同,这将在重复键上抛出`System.ArgumentException`而不是返回`false`. (3认同)
  • 它调用`Remove(TKey)`因为它是派生类最多的类.但是,当集合被转换为Collection <T>或ICollection <T>时调用Remove()将调用`Remove(T)`重载. (2认同)

Ond*_*lka 6

如果你需要不断的复杂性AddRemoveContains和订单保存,再有就是在.NET框架4.5没有这样的集合。

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

OrderedHashSet<T>集合:

  • 基于经典HashSet<T>源代码(来自.NET Core)
  • 保留插入顺序并允许手动重新排序
  • 功能反转枚举
  • 具有相同的操作复杂性HashSet<T>
  • AddRemove操作相比,速度要慢20%HashSet<T>
  • 每个项目消耗8个以上的内存字节