Pytanie Kolekcja, która pozwala tylko unikalne elementy w .NET?


Czy istnieje kolekcja w języku C #, która nie pozwala na dodawanie do niej duplikatów? Na przykład z głupią klasą

public class Customer {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }

    public override int GetHashCode() {
        return (FirstName + LastName + Address).GetHashCode();
    }

    public override bool Equals(object obj) {
        Customer C = obj as Customer;
        return C != null && String.Equals(this.FirstName, C.FirstName) && String.Equals(this.LastName, C.LastName) && String.Equals(this.Address, C.Address);
    }
}

Poniższy kod (oczywiście) rzuci wyjątek:

Customer Adam = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Customer AdamDup = new Customer { Address = "A", FirstName = "Adam", LastName = "" };

Dictionary<Customer, bool> CustomerHash = new Dictionary<Customer, bool>();
CustomerHash.Add(Adam, true);
CustomerHash.Add(AdamDup, true);

Ale czy istnieje klasa, która podobnie zagwarantuje wyjątkowość, ale bez KeyValuePairs? myślałem HashSet<T> zrobiłby to, ale po przeczytaniu dokumentów wydaje się, że klasa to tylko ustalona implementacja (domyśl).


76
2018-03-01 17:08


pochodzenie


Nie rozumiem twojego problemu HashSet<T>. MSDN mówi: "Klasa HashSet <T> zapewnia wysokiej jakości operacje zestawów. Zbiór jest kolekcją, która nie zawiera żadnych duplikatów elementów i której elementy nie występują w określonej kolejności." - Daniel Hilgarth
Czy możesz wyjaśnić więcej dlaczego? HashSet<T> jest niewystarczające? - JaredPar
@mootinator: The Dictionary<K,V> klasa nie gwarantować każdy rodzaj zamówienia. - LukeH
Chyba chce rzucić wyjątek, gdy próbujesz dodać istniejącą wartość ... Aby to zrobić, po prostu sprawdź wartość bool zwróconą przez HashSet<T>.Add metoda i rzuć kiedy false... - digEmAll
Zaleca się również, aby przeciążać tylko te niezmienny tylko typy. Zmienny klient zazwyczaj lepiej radzi sobie z domyślną równością referencyjną. - Henk Holterman


Odpowiedzi:


HashSet<T> jest tym, czego szukasz. Od MSDN (wyróżnienia dodane):

The HashSet<T> klasa zapewnia wysoką wydajność operacji zestaw. Zestaw to kolekcja, która nie zawiera żadnych duplikatów elementówi których elementy nie są w określonej kolejności.

Zauważ, że HashSet<T>.Add(T item) metoda zwraca a bool - true jeśli przedmiot został dodany do kolekcji; false jeśli przedmiot był już obecny.


159
2018-03-01 17:12





Co powiesz na samą metodę rozszerzenia w HashSet?

public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
    if (!hash.Add(item))
        throw new ValueExistingException();
}

16
2017-07-03 20:14





Od HashSet<T> strona na MSDN:

Klasa HashSet (Of T) zapewnia operację zestawu o wysokiej wydajności. Zestaw to kolekcja, która nie zawiera żadnych duplikatów elementówi których elementy nie są w określonej kolejności.

(nacisk mój)


10
2018-03-01 17:11





Możesz spróbować HashSet<T>


4
2018-03-01 17:11



meta.stackoverflow.com/tags/link-only-answers/info - Jonathon Reinhart


Jeśli wszystko, czego potrzebujesz, to zapewnić wyjątkowość elementów, to HashSet jest tym, czego potrzebujesz.

Co masz na myśli, gdy mówisz "tylko ustalona implementacja"? Zestaw jest (z definicji) zbiorem unikatowych elementów, które nie zapisują porządku elementów.


3
2018-03-01 17:13



Masz całkowitą rację; pytanie było trochę głupie. Zasadniczo szukałem czegoś, co rzuciłoby wyjątek po dodaniu duplikatu (np. Słownik <TKey, TValue>), ale jak już wspomniano, HashSet <T> zwraca fałsz na duplikacie. +1, dziękuję. - Adam Rackis


Aby dodać moje 2 centy ...

jeśli potrzebujesz rzutu o wartości ValueExistingException HashSet<T> możesz także łatwo stworzyć swoją kolekcję:

public class ThrowingHashSet<T> : ICollection<T>
{
    private HashSet<T> innerHash = new HashSet<T>();

    public void Add(T item)
    {
        if (!innerHash.Add(item))
            throw new ValueExistingException();
    }

    public void Clear()
    {
        innerHash.Clear();
    }

    public bool Contains(T item)
    {
        return innerHash.Contains(item);
    }

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

    public int Count
    {
        get { return innerHash.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        return innerHash.Remove(item);
    }

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

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

może to być przydatne na przykład, jeśli potrzebujesz go w wielu miejscach ...


1
2018-03-01 19:03



Pewnie. Zastanawiałem się, czy coś jest wbudowane, ale dziękuję +1 - Adam Rackis