Подтвердить что ты не робот

Что эквивалентно LinkedHashSet (Java) в С#?

Что такое эквивалент LinkedHashSet (Java) в С#?

4b9b3361

Ответ 1

Я закончил незавершенные методы и вообще отполировал класс, который опубликовал "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();
    }

}

Необходимые операции:

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

Предупреждение. Класс в основном не проверен, особенно методы ISet. Используйте на свой страх и риск.
Надеюсь, кто-то найдет это полезным.:)

Ответ 2

В С# нет прямого эквивалента. Соответствующий класс для использования зависит от желаемого поведения. Класс HashSet сохранит уникальность элементов. Вы также можете проверить SortedSet и SortedDictionary.

В С# нет класса, который объединяет связанный список с уникальностью, требуемой в структуре данных Set, поэтому, если вам нужны оба поведения, вам нужно будет создать свой собственный.

Ответ 3

Я кратко выполнил 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 выполняет эту работу, потому что она фактически эквивалентна LinkedHashSet в Java. HashSet поддерживается связанным списком, хотя в документах явно не указано, что он сохраняет заказ или поддерживает его на основе массива. Вы можете видеть из исходный код реализация - это LinkedHashSet.

Дубликаты не допускаются так же, как Java LinkedHashSet. Единственное различие между этим и LinkedHashSet заключается в том, что если вы удаляете что-то из набора, он только отмечает элемент как свободный в массиве, и поэтому добавление элемента после удаления() заполняет первые слоты массива перед "добавлением". Способ вокруг этого - вызвать метод 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