2012-02-19 28 views
13

C#のLinkedHashSet(Java)に相当するものは何ですか?C#でLinkedHashSet(Java)に相当するものは何ですか?

+0

あなたはLinkedHashSetの内容を説明場合には罰金になります:) – demas

+0

これは、挿入順序を維持セットです。バッキングリンクされたリストを使用して行います。 – duffymo

+0

の可能な複製[なぜHashSetがC#で設定されていないのですか?](http://stackoverflow.com/questions/1023697/why-have-hash-but-not-set-in-c) – duffymo

答えて

9

私は未完成の方法を完了し、一般的に 'achitaka-san'が投稿したクラスを研磨しました。

public class LinkedHashSet<T> : ISet<T> { 

    private readonly IDictionary<T, LinkedListNode<T>> dict; 
    private readonly LinkedList<T> list; 

    public LinkedHashSet(int initialCapacity) { 
     this.dict = new Dictionary<T,LinkedListNode<T>>(initialCapacity); 
     this.list = new LinkedList<T>(); 
    } 

    public LinkedHashSet() { 
     this.dict = new Dictionary<T,LinkedListNode<T>>(); 
     this.list = new LinkedList<T>(); 
    } 

    public LinkedHashSet(IEnumerable<T> e) : this() { 
     addEnumerable(e); 
    } 

    public LinkedHashSet(int initialCapacity, IEnumerable<T> e) : this(initialCapacity) { 
     addEnumerable(e); 
    } 

    private void addEnumerable(IEnumerable<T> e) { 
     foreach (T t in e) { 
      Add(t); 
     } 
    } 

    // 
    // ISet implementation 
    // 

    public bool Add(T item) { 
     if (this.dict.ContainsKey(item)) { 
      return false; 
     } 
     LinkedListNode<T> node = this.list.AddLast(item); 
     this.dict[item] = node; 
     return true; 
    } 

    public void ExceptWith(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     foreach (T t in other) { 
      Remove(t); 
     } 
    } 

    public void IntersectWith(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     T[] ts = new T[Count]; 
     CopyTo(ts, 0); 
     foreach (T t in ts) { 
      if (!System.Linq.Enumerable.Contains(other, t)) { 
       Remove(t); 
      } 
     } 
    } 

    public bool IsProperSubsetOf(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     int contains = 0; 
     int noContains = 0; 
     foreach (T t in other) { 
      if (Contains(t)) { 
       contains++; 
      } else { 
       noContains++; 
      } 
     } 
     return contains == Count && noContains > 0; 
    } 

    public bool IsProperSupersetOf(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     int otherCount = System.Linq.Enumerable.Count(other); 
     if (Count <= otherCount) { 
      return false; 
     } 
     int contains = 0; 
     int noContains = 0; 
     foreach (T t in this) { 
      if (System.Linq.Enumerable.Contains(other, t)) { 
       contains++; 
      } else { 
       noContains++; 
      } 
     } 
     return contains == otherCount && noContains > 0; 
    } 

    public bool IsSubsetOf(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     foreach (T t in this) { 
      if (!System.Linq.Enumerable.Contains(other, t)) { 
       return false; 
      } 
     } 
     return true; 
    } 

    public bool IsSupersetOf(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     foreach (T t in other) { 
      if (!Contains(t)) { 
       return false; 
      } 
     } 
     return true; 
    } 

    public bool Overlaps(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     foreach (T t in other) { 
      if (Contains(t)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    public bool SetEquals(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     int otherCount = System.Linq.Enumerable.Count(other); 
     if (Count != otherCount) { 
      return false; 
     } 
     return IsSupersetOf(other); 
    } 

    public void SymmetricExceptWith(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     T[] ts = new T[Count]; 
     CopyTo(ts, 0); 
     HashSet<T> otherList = new HashSet<T>(other); 
     foreach (T t in ts) { 
      if (otherList.Contains(t)) { 
       Remove(t); 
       otherList.Remove(t); 
      } 
     } 
     foreach (T t in otherList) { 
      Add(t); 
     } 
    } 

    public void UnionWith(IEnumerable<T> other) { 
     if (other == null) { 
      throw new ArgumentNullException("other cannot be null"); 
     } 
     foreach (T t in other) { 
      Add(t); 
     } 
    } 

    // 
    // ICollection<T> implementation 
    // 

    public int Count { 
     get { 
      return this.dict.Count; 
     } 
    } 

    public bool IsReadOnly { 
     get { 
      return this.dict.IsReadOnly; 
     } 
    } 

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

    public void Clear() { 
     this.dict.Clear(); 
     this.list.Clear(); 
    } 

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

    public void CopyTo(T[] array, int arrayIndex) { 
     this.list.CopyTo(array, arrayIndex); 
    } 

    public bool Remove(T item) { 
     LinkedListNode<T> node; 
     if (!this.dict.TryGetValue(item, out node)) { 
      return false; 
     } 
     this.dict.Remove(item); 
     this.list.Remove(node); 
     return true; 
    } 

    // 
    // IEnumerable<T> implementation 
    // 

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

    // 
    // IEnumerable implementation 
    // 

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

} 

必要usings:

using System; 
using System.Collections; 
using System.Collections.Generic; 

警告:このクラスは、特にISET法大部分は未テストです。自己責任。
誰かがこの点を知りたがっていれば幸いです。 :)

8

C#では直接的な機能はありません。使用する適切なクラスは、望ましい動作に依存します。 HashSetクラスは、要素の一意性を保持します。また、SortedSetSortedDictionaryをチェックすることもできます。

リンクされたリストとセットデータ構造に必要な一意性を組み合わせたクラスはありません。したがって、両方の動作が必要な場合は、自分でビルドする必要があります。

5

私は簡単にHashSetを実装しており、挿入の順序を保証しています。項目を検索するにはDictionary、注文を保存するにはLinkedListを使用します。 3つの挿入、削除、検索はすべてO(1)のままです。

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

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

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

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

    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 int Count 
    { 
     get { return m_Dictionary.Count; } 
    } 

    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); 
    } 


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

    public void UnionWith(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public void IntersectWith(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public void ExceptWith(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public bool IsSubsetOf(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public void SymmetricExceptWith(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public bool IsSupersetOf(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public bool IsProperSupersetOf(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public bool IsProperSubsetOf(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public bool Overlaps(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    public bool SetEquals(IEnumerable<T> other) 
    { 
     throw GetNotSupportedDueToSimplification(); 
    } 

    private static Exception GetNotSupportedDueToSimplification() 
    { 
     return new NotSupportedException("This method is not supported due to simplification of example code."); 
    } 
} 
4

JavaのLinkedHashSetと事実上同等であるため、HashSetはジョブを実行します。 HashSetはリンクされたリストによってサポートされていますが、ドキュメントには順序が保持されていること、または配列ベースのリンクされたリストによって保持されていることが明示されていません。 the source codeから、実装がLinkedHashSetであることがわかります。

Java LinkedHashSetと同じように重複は許可されません。これとLinkedHashSetの違いの1つは、セットから何かを削除すると、配列内の要素を空きとしてマークするだけなので、remove()の後に項目を追加すると空の配列スロットが最初に「追加」されます。これを回避する方法は、TrimExcess()メソッドを呼び出すことです。したがって、多くのユースケースでは全く同じではありませんが、シリアライズしてデシリアライズし、効果的に変更不可能なセットを作成した場合はうまく動作します。

常にremove()をサブクラス化してオーバーライドして、常に同じ動作を得るためにTrimExcess()を呼び出すことができます。また、LinkedHashSetクラスの名前を明確にすることができます!

using System; 
using System.Collections.Generic; 


namespace ConsoleApplication 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      String[] crew = {"Spock", "Kirk", "Bones", "Picard", "Uhura", "Chekov"}; 
      HashSet<String> linkedHashSet = new HashSet<String>(crew); 

      // Show order is preserved 
      foreach(String value in linkedHashSet){ 
       Console.Write(value); Console.Write(" "); 
      } 

      // Remove from the middle 
      linkedHashSet.Remove("Picard"); 
      Console.WriteLine(); 
      foreach(String value in linkedHashSet){ 
       Console.Write(value); Console.Write(" "); 
      } 

      // Add it back but it is back in the middle not the end 
      linkedHashSet.Add("Picard"); 
      Console.WriteLine(); 
      foreach(String value in linkedHashSet){ 
       Console.Write(value); Console.Write(" "); 
      } 

      // Remove and trim then add 
      linkedHashSet.Remove("Picard"); 
      linkedHashSet.TrimExcess(); 
      linkedHashSet.Add("Picard"); 
      Console.WriteLine(); 
      foreach(String value in linkedHashSet){ 
       Console.Write(value); Console.Write(" "); 
      } 
      Console.WriteLine(); 
     } 
    } 
} 

出力:

Spock Kirk Bones Picard Uhura Chekov 
Spock Kirk Bones Uhura Chekov 
Spock Kirk Bones Picard Uhura Chekov 
Spock Kirk Bones Uhura Chekov Picard 
関連する問題