挿入順序を保持するHashSetが必要ですが、フレームワークにこれを実装したものはありますか?
標準の.NET HashSet
は挿入順序を保持しません。簡単なテストでは、事故のために挿入順序が保持される場合がありますが、保証されておらず、常にそのように機能するとは限りません。間にいくつかの削除を行うだけで十分であることを証明するため。
詳細については、この質問を参照してください。 HashSetは挿入順序を保持しますか?
挿入順序を保証するHashSet
を簡単に実装しました。 Dictionary
を使用してアイテムを検索し、LinkedList
を使用して順序を保持します。 3つの挿入、削除、ルックアップはすべて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);
}
}
この機能は、TKeyとTItemに同じ型引数を指定して KeyedCollection<TKey,TItem>
を使用して簡単に取得できます。
public class OrderedHashSet<T> : KeyedCollection<T, T>
{
protected override T GetKeyForItem(T item)
{
return item;
}
}
Add
、Remove
、Contains
の一定の複雑さと順序の保持が必要な場合、.NET Framework4.5にはそのようなコレクションはありません。
サードパーティのコードで問題がない場合は、私のリポジトリを見てください(permissive MIT license): https://github.com/OndrejPetrzilka/Rock.Collections ==
OrderedHashSet<T>
コレクションがあります:
HashSet<T>
ソースコード(.NET Coreから)に基づくHashSet<T>
と同じ操作の複雑さがありますAdd
およびRemove
の操作は、HashSet<T>
と比較して20%遅くなります。