.NET'te yalnızca benzersiz öğelere izin veren koleksiyon?


104

C # içinde, ona yinelenen öğeler eklemenize izin vermeyecek bir koleksiyon var mı? Örneğin, aptal sınıfıyla

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

Aşağıdaki kod (açıkça) bir istisna oluşturacaktır:

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

Ancak benzer şekilde benzersizliği garanti edecek, ancak KeyValuePairs olmadan bir sınıf var mı? Bunu HashSet<T>yapacağımı düşünmüştüm , ancak dokümanları okuduktan sonra, sınıf sadece bir set uygulaması gibi görünüyor ( şekle bakın ).


4
Sorununu anlamıyorum HashSet<T>. MSDN, "HashSet <T> sınıfı, yüksek performanslı küme işlemleri sağlar. Küme, yinelenen öğeler içermeyen ve öğeleri belirli bir sırada olmayan bir koleksiyondur."
Daniel Hilgarth

5
Neden HashSet<T>yetersiz olduğunu biraz daha açıklayabilir misin ?
JaredPar

@mootinator: Dictionary<K,V>sınıf değil sırayla her türlü garanti.
LukeH

3
Sanırım mevcut bir değeri eklemeye çalıştığınızda sadece bir istisna atmak istiyor ... Bunu yapmak için, HashSet<T>.Addyöntemden döndürülen bool değerini kontrol edin ve şunu atın false...
digEmAll

2
Ayrıca, yalnızca değişmez türler için olanları aşırı yüklemeniz kesinlikle önerilir . Değişken bir Müşteri, varsayılan Referans eşitliği ile genellikle daha adil olur.
Henk Holterman

Yanıtlar:


206

HashSet<T>aradığınız şey. Gönderen MSDN (vurgu eklenmiştir):

HashSet<T>Sınıf yüksek performanslı seti işlemler sağlar. Küme, yinelenen öğeler içermeyen ve öğeleri belirli bir sırada olmayan bir koleksiyondur .

HashSet<T>.Add(T item)Yöntemin , öğe koleksiyona eklenmişse bir bool- döndürdüğünü unutmayın true; falseöğe zaten mevcutsa.


9
Bu durumda T öğesi IEquatable arabirimini uygulamalıdır. Sınıf bu arabirimi devralmazsa, HashSet <T> yinelenen öğeler ekler.
Rudolf Dvoracek

Ya da öğe uygulama yerine, IEquatableyapıcıya bir (özel) EqualityComparer<T>örnek uygulaması geçirebilirsiniz HashSet<T>.
Sipke Schoorstra

17

HashSet'te sadece bir uzatma yöntemine ne dersiniz?

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

13

MSDN'deki HashSet<T>sayfadan:

HashSet (Of T) sınıfı, yüksek performanslı set işlemleri sağlar. Küme, yinelenen öğeler içermeyen ve öğeleri belirli bir sırada olmayan bir koleksiyondur .

(vurgu benim)


4

İhtiyacınız olan tek şey öğelerin benzersizliğini sağlamaksa, ihtiyacınız olan şey HashSet'dir.

"Sadece set uygulaması" derken neyi kastediyorsunuz? Küme, (tanım gereği) öğe sırasını kaydetmeyen benzersiz öğeler koleksiyonudur.


Tamamen haklısın; soru biraz aptalcaydı. Temel olarak, bir kopya eklendiğinde (Dictionary <TKey, TValue> gibi) bir istisna atacak bir şey arıyordum, ancak daha önce de belirtildiği gibi, HashSet <T> yinelenen bir eklemede false döndürüyor. +1, teşekkür ederim.
Adam Rackis


3

Sadece 2 sentimi eklemek için ...

Bir ValueExistingException özelliğine ihtiyacınız varsa HashSet<T>, koleksiyonunuzu da kolayca oluşturabilirsiniz:

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

bu yararlı olabilir, örneğin birçok yerde ihtiyacınız varsa ...


Elbette.
Yerleşik bir

0

Aşağıdaki gibi Eşsiz Listeye bakabilirsiniz.

public class UniqueList<T>
{
    public List<T> List
    {
        get;
        private set;
    }
    List<T> _internalList;

    public static UniqueList<T> NewList
    {
        get
        {
            return new UniqueList<T>();
        }
    }

    private UniqueList()
    {            
        _internalList = new List<T>();
        List = new List<T>();
    }

    public void Add(T value)
    {
        List.Clear();
        _internalList.Add(value);
        List.AddRange(_internalList.Distinct());
        //return List;
    }

    public void Add(params T[] values)
    {
        List.Clear();
        _internalList.AddRange(values);
        List.AddRange(_internalList.Distinct());
       // return List;
    }

    public bool Has(T value)
    {
        return List.Contains(value);
    }
}

ve aşağıdaki gibi kullanabilirsiniz

var uniquelist = UniqueList<string>.NewList;
uniquelist.Add("abc","def","ghi","jkl","mno");
uniquelist.Add("abc","jkl");
var _myList = uniquelist.List;

yalnızca "abc","def","ghi","jkl","mno"kopyalar eklendiğinde bile her zaman döndürülür

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.