2012-02-19 89 views
13

C#中LinkedHashSet(Java)的等價物是什麼?什麼是C#中LinkedHashSet(Java)的等價物?

+0

如果你的描述LinkedHashSet做:) – demas 2012-02-19 03:55:18

+0

這是一組保持插入順序它會沒事的。它使用一個支持鏈表來做到這一點。 – duffymo 2012-02-19 03:59:06

+0

可能的重複[爲什麼有HashSet但未在C#中設置?](http://stackoverflow.com/questions/1023697/why-have-hashset-but-not-set-in-c) – duffymo 2012-02-19 04:00:17

回答

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

C#中沒有類將鏈接列表與集合數據結構中所需的唯一性結合起來,因此如果您需要這兩種行爲,那麼您將需要構建自己的行爲。

5

我簡要實施了一個確保廣告訂單的HashSet。它使用Dictionary來查找項目,並使用LinkedList來維護訂單。所有三個插入,刪除和查找工作仍在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

HashSet執行該任務,因爲它幾乎等同於Java中的LinkedHashSet。 HashSet由鏈表支持 - 雖然文檔沒有明確聲明它保留了順序或者它是由基於數組的鏈接列表支持的。你可以從the source code看到實現是一個LinkedHashSet。

不允許重複,就像Java LinkedHashSet一樣。這與LinkedHashSet的區別在於,如果你從集合中刪除了某些東西,它只會將該元素標記爲數組中的空閒元素,因此在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 
相關問題