web-dev-qa-db-ja.com

リストに一意のアイテムのみを追加

ネットワークを介して自分自身をアナウンスするときに、リモートデバイスをリストに追加しています。デバイスがまだ追加されていない場合にのみ、リストにデバイスを追加します。

デバイスを追加するコードを複数のスレッドで実行できるように、アナウンスは非同期ソケットリスナーに渡されます。何が間違っているのかはわかりませんが、何をしようとしても重複することになります。ここに私が現在持っているものがあります.....

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

要件に重複がない場合は、 HashSet を使用する必要があります。

HashSet.Add は、アイテムが既に存在する場合にfalseを返します(それが問題になる場合もあります)。

@pstrjdsが以下にリンクしているコンストラクター(または here )を使用して等値演算子を定義するか、RemoteDeviceGetHashCodeEquals)で等値メソッドを実装する必要があります。

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

受け入れられた答えが言うように、HashSetには注文がありません。順序が重要な場合は、リストを引き続き使用して、追加する前にリストにアイテムが含まれているかどうかを確認できます。

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

カスタムクラス/オブジェクトでList.Contains()を実行するには、カスタムクラスでIEquatable<T>を実装するか、Equalsをオーバーライドする必要があります。クラスにもGetHashCodeも実装することをお勧めします。これは 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;
    }
}
8
Luke Eckley

いくつかの一般性を得るための拡張メソッドとして記述でき、オプションのカスタム比較を渡すことができます...

/// <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();
}
2
Paul Hatcher