web-dev-qa-db-fra.com

Collection qui autorise uniquement les éléments uniques dans .NET?

Existe-t-il une collection en C # qui ne vous permette pas d'y ajouter des éléments en double? Par exemple, avec la classe idiote de

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

Le code suivant lève (évidemment) une exception:

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

Mais existe-t-il une classe qui garantira de la même manière l'unicité, mais sans KeyValuePairs? J'ai pensé HashSet<T> ferait cela, mais après avoir lu la documentation, il semblerait que la classe ne soit qu'une implémentation définie (voir figure).

96
Adam Rackis

HashSet<T> Est ce que vous recherchez. De MSDN (emphase ajoutée):

La classe HashSet<T> Fournit des opérations d'ensemble performantes. Un ensemble est une collection qui ne contient aucun élément en double et dont les éléments ne sont dans aucun ordre particulier.

Notez que la méthode HashSet<T>.Add(T item)) renvoie un bool - true si l'élément a été ajouté à la collection; false si l'élément était déjà présent.

191
Donut

Que diriez-vous d'une méthode d'extension sur HashSet?

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

Du HashSet<T> page sur MSDN:

La classe HashSet (Of T) fournit des opérations d'ensemble performantes. Un ensemble est une collection qui ne contient aucun élément en double et dont les éléments ne sont dans aucun ordre particulier.

(c'est moi qui souligne)

13
Oded

Si tout ce dont vous avez besoin est de garantir l'unicité des éléments, alors HashSet est ce qu'il vous faut.

Que voulez-vous dire quand vous dites "juste une implémentation définie"? Un ensemble est (par définition) une collection d'éléments uniques qui n'enregistre pas l'ordre des éléments.

4
Lloyd

Juste pour ajouter mes 2 centimes ...

si vous avez besoin d'un jeton ValueExistingException HashSet<T> vous pouvez également créer facilement votre collection:

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

cela peut être utile par exemple si vous en avez besoin à plusieurs endroits ...

3
digEmAll

Tu peux essayer HashSet<T>

3
Cheng Chen

Vous pouvez regarder dans quelque chose comme une liste unique comme suit

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

et vous pouvez l'utiliser comme suit

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

ne retournera que "abc","def","ghi","jkl","mno" toujours même lorsque des doublons y sont ajoutés

0
Vinod Srivastav