web-dev-qa-db-fra.com

Ajouter uniquement un élément unique à la liste

J'ajoute des périphériques distants à une liste au fur et à mesure qu'ils s'annoncent sur le réseau. Je souhaite uniquement ajouter l'appareil à la liste s'il n'a pas déjà été ajouté. 

Les annonces rencontrent un écouteur de socket asynchrone afin que le code pour ajouter un périphérique puisse être exécuté sur plusieurs threads. Je ne suis pas sûr de ce que je fais mal mais peu importe ce que j'essaie, je me retrouve avec des duplications. Voici ce que j'ai actuellement .....

lock (_remoteDevicesLock)
{
    RemoteDevice rDevice = (from d in _remoteDevices
                            where d.UUID.Trim().Equals(notifyMessage.UUID.Trim(), StringComparison.OrdinalIgnoreCase)
                            select d).FirstOrDefault();
     if (rDevice != null)
     {
         //Update Device.....
     }
     else
     {
         //Create A New Remote Device
         rDevice = new RemoteDevice(notifyMessage.UUID);
         _remoteDevices.Add(rDevice);
     }
}
57
Oli

Si vos exigences ne doivent pas contenir de doublons, utilisez un HashSet .

HashSet.Add retournera false lorsque l'élément existe déjà (si cela vous concerne).

Vous pouvez utiliser le constructeur auquel @pstrjds fait référence ci-dessous (ou ici ) pour définir l'opérateur d'égalité ou vous devrez implémenter les méthodes d'égalité dans RemoteDevice (GetHashCode & Equals).

116
Austin Salonen
//HashSet allows only the unique values to the list
HashSet<int> uniqueList = new HashSet<int>();

var a = uniqueList.Add(1);
var b = uniqueList.Add(2);
var c = uniqueList.Add(3);
var d = uniqueList.Add(2); // should not be added to the list but will not crash the app

//Dictionary allows only the unique Keys to the list, Values can be repeated
Dictionary<int, string> dict = new Dictionary<int, string>();

dict.Add(1,"Happy");
dict.Add(2, "Smile");
dict.Add(3, "Happy");
dict.Add(2, "Sad"); // should be failed // Run time error "An item with the same key has already been added." App will crash

//Dictionary allows only the unique Keys to the list, Values can be repeated
Dictionary<string, int> dictRev = new Dictionary<string, int>();

dictRev.Add("Happy", 1);
dictRev.Add("Smile", 2);
dictRev.Add("Happy", 3); // should be failed // Run time error "An item with the same key has already been added." App will crash
dictRev.Add("Sad", 2);
12

Tout comme la réponse acceptée indique qu'un HashSet n'a pas d'ordre. Si l'ordre est important, vous pouvez continuer à utiliser une liste et vérifier si elle contient l'élément avant de l'ajouter.

if (_remoteDevices.Contains(rDevice))
    _remoteDevices.Add(rDevice);

Pour exécuter List.Contains () sur une classe/un objet personnalisé, vous devez implémenter IEquatable<T> sur la classe personnalisée ou redéfinir la variable Equals. C'est une bonne idée d'implémenter également GetHashCode dans la classe. Ceci est décrit dans la documentation à https://msdn.Microsoft.com/en-us/library/ms224763.aspx

public class RemoteDevice: IEquatable<RemoteDevice>
{
    private readonly int id;
    public RemoteDevice(int uuid)
    {
        id = id
    }
    public int GetId
    {
        get { return id; }
    }

    // ...

    public bool Equals(RemoteDevice other)
    {
        if (this.GetId == other.GetId)
            return true;
        else
            return false;
    }
    public override int GetHashCode()
    {
        return id;
    }
}
6
Luke Eckley

Peut être écrit comme une méthode d’extension pour obtenir une certaine généralité et vous pouvez passer un comparateur facultatif ...

/// <summary>
/// Generates a new list with only distinct items preserving original ordering.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IList<T> ToUniqueList<T>(this IList<T> list, IEqualityComparer<T> comparer = null)
{
    bool Contains(T x) => comparer == null ? list.Contains(x) : list.Contains(x, comparer);

    return list.Where(entity => !Contains(entity)).ToList();
}
1
Paul Hatcher