保留排序的HashSet

时间:2009-10-12 00:42:50

标签: c# .net hashset

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

3 个答案:

答案 0 :(得分:24)

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

有关详细信息,请参阅此问题:Does HashSet preserve insertion order?

我已经简要地实施了一个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);
    }
}

答案 1 :(得分:18)

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

public class OrderedHashSet<T> : KeyedCollection<T, T>
{
    protected override T GetKeyForItem(T item)
    {
        return item;
    }
}

答案 2 :(得分:5)

如果您需要AddRemoveContains和订单保留的持续复杂性,那么.NET Framework 4.5中就没有这样的集合。

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

OrderedHashSet<T>集合:

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