2012-02-19 14 views
13

Qual è l'equivalente di un LinkedHashSet (Java) in C#?Qual è l'equivalente di LinkedHashSet (Java) in C#?

+0

Sarà bene se si descrivere cosa LinkedHashSet fare :) – demas

+0

E 'un set che mantiene l'ordine di inserimento. Usa una lista di supporto per farlo. – duffymo

+0

possibile duplicato di [Perché HashSet non è impostato in C#?] (Http://stackoverflow.com/questions/1023697/why-have-hashset-but-not-set-in-c) – duffymo

risposta

9

ho completato i metodi non finiti e, in generale lucido la classe che 'achitaka-san' postato.

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 richiesti:

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

Attenzione: La classe è in gran parte non testato, in particolare ai metodi Iset. Utilizzare a proprio rischio.
Spero che qualcuno lo trovi utile. :)

8

Non esiste un equivalente diretto in C#. La classe appropriata da utilizzare dipende dal comportamento desiderato. La classe HashSet preserverà l'unicità degli elementi. Potresti anche voler dare un'occhiata a SortedSet e SortedDictionary.

Non esiste una classe in C# che combini una lista collegata con unicità richiesta in una struttura di dati Set, quindi se avete bisogno di entrambi i comportamenti, allora dovrete creare il vostro.

5

Ho implementato brevemente un HashSet che garantisce l'ordine di inserimento. Utilizza lo Dictionary per cercare gli articoli e lo LinkedList per conservare l'ordine. Tutti e tre gli inserimenti, la rimozione e la ricerca funzionano ancora in 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 fa il lavoro perché è praticamente equivalente a LinkedHashSet in Java. HashSet è supportato da un elenco collegato, anche se i documenti non dichiarano esplicitamente che conserva l'ordine o che è supportato da un elenco collegato basato su array. È possibile vedere da the source code l'implementazione è un LinkedHashSet.

I duplicati non sono consentiti proprio come Java LinkedHashSet. L'unica differenza tra questo e LinkedHashSet è che se rimuovi qualcosa dal set, contrassegna solo l'elemento come libero nell'array, e quindi aggiungendo un elemento dopo un remove() riempie gli slot di array vuoti prima di "accodare". Il modo per aggirare questo è chiamare il metodo TrimExcess(). Pertanto, anche se non è esattamente la stessa in molti casi d'uso, ad es. serializza e deserializza e per insiemi effettivamente immutabili una volta creato funziona alla grande.

È sempre possibile eseguire la sottoclasse e l'override di remove() per chiamare sempre TrimExcess() per ottenere lo stesso comportamento. E puoi dare un nome alla classe LinkedHashSet per chiarezza!

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

uscita:

Spock Kirk Bones Picard Uhura Chekov 
Spock Kirk Bones Uhura Chekov 
Spock Kirk Bones Picard Uhura Chekov 
Spock Kirk Bones Uhura Chekov Picard 
Problemi correlati