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


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


14
2018-02-19 03:52


origine


risposte:


Ho completato i metodi incompiuti e in generale ho lucidato la classe che ha pubblicato '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();
    }

}

Usi richiesti:

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

Avvertenza: la classe non è stata testata, in particolare i metodi ISet. Utilizzare a proprio rischio.
Spero che qualcuno lo trovi utile. :)


9
2017-07-14 23:42



Non esiste un equivalente diretto in C #. La classe appropriata da utilizzare dipende dal comportamento desiderato. Il HashSet la classe preserverà l'unicità degli elementi. Potresti anche voler controllare 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 hai bisogno di entrambi i comportamenti, dovrai creare il tuo.


8
2018-02-19 03:58



Ho implementato brevemente a HashSet che garantisce l'ordine di inserimento. Usa il Dictionary cercare oggetti e il LinkedList per preservare 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.");
    }
}

5
2017-07-25 15:05



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. Puoi vedere da il codice sorgente 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.

Puoi sempre creare sottoclassi e override 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();
        }
    }
}

Produzione:

Spock Kirk Bones Picard Uhura Chekov
Spock Kirk Bones Uhura Chekov
Spock Kirk Bones Picard Uhura Chekov
Spock Kirk Bones Uhura Chekov Picard

4
2018-01-10 21:14