web-dev-qa-db-ja.com

オブジェクトがリストに既に存在するかどうかを確認する方法

リストがあります

  List<MyObject> myList

リストにアイテムを追加していますが、そのオブジェクトが既にリストにあるかどうかを確認したいと思います。

だから私はこれを行う前に:

 myList.Add(nextObject);

NextObjectが既にリストにあるかどうかを確認したい。

オブジェクト「MyObject」には多くのプロパティがありますが、比較は2つのプロパティの一致に基づいています。

この「MyObject」のリストに新しい「MyObject」を追加する前にチェックを行う最善の方法は何ですか。

私が考えた唯一の解決策は、リストから辞書に変更してから、キーをプロパティの連結文字列にすることでした(これは少し違法なようです)。

リストやLINQなどを使用した他のクリーナーソリューションはありますか?

79
leora

特定の状況のニーズによって異なります。たとえば、辞書アプローチは次の場合に非常に適しています。

  1. リストは比較的安定しています(多くの挿入/削除ではなく、辞書は最適化されていません)
  2. リストは非常に大きくなります(それ以外の場合、辞書のオーバーヘッドは無意味です)。

上記に当てはまらない場合は、Any()を使用してください

Item wonderIfItsPresent = ...
bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);'

これは、一致が見つかるまで、または最後に達するまでリストを列挙します。

124
Rex M

含む メソッドを使用します。等式関数Equalsに基づいて機能することに注意してください

bool alreadyExist = list.Contains(item);
68
Ahmad

これらの2つのプロパティを使用して保守できる場合、次のことができます。

bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");
48
p.campbell

この場合、リストが必要ですか?リストに多数の項目を追加している場合、myList.ContainsまたはmyList.Any;でパフォーマンスが低下します。ランタイムは2次になります。より良いデータ構造の使用を検討することをお勧めします。例えば、

 public class MyClass
    {
        public string Property1 { get; set; }
        public string Property2 { get; set; }

    }

    public class MyClassComparer : EqualityComparer<MyClass>
    {
        public override bool Equals(MyClass x, MyClass y)
        {
            if(x == null || y == null)
               return x == y;

            return x.Property1 == y.Property1 && x.Property2 == y.Property2;
        }

        public override int GetHashCode(MyClass obj)
        {
            return obj == null ? 0 : (obj.Property1.GetHashCode() ^ obj.Property2.GetHashCode());
        }
    }

HashSetは次の方法で使用できます。

  var set = new HashSet<MyClass>(new MyClassComparer());
  foreach(var myClass in ...)
     set.Add(myClass);

もちろん、MyClassの平等のこの定義が「ユニバーサル」である場合、IEqualityComparer実装を記述する必要はありません。クラス自体のGetHashCodeEqualsをオーバーライドするだけで済みます。

7
Ani

言及する別のポイントは、平等関数が期待どおりであることを確認する必要があるということです。 equalsメソッドをオーバーライドして、2つのインスタンスが等しいと見なされるためにオブジェクトのどのプロパティを一致させる必要があるかを設定する必要があります。

次に、mylist.contains(item)を実行します。

編集:私は最初に言った:


ディクショナリソリューションの洗練されていないもの。辞書の作成時にコンパレーターを設定するだけでよいので、特に私には完璧に思えます。


もちろん、それが値でもあるときに何かをキーとして使用することは洗練されていません。

したがって、HashSetを使用します。後の操作でインデックス作成が必要な場合は、追加が完了したときにリストからリストを作成します。それ以外の場合は、ハッシュセットを使用します。

3
Jon Hanna

以下は、問題を解決する方法の概念を示すクイックコンソールアプリです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    public class myobj
    {
        private string a = string.Empty;
        private string b = string.Empty;

        public myobj(string a, string b)
        {
            this.a = a;
            this.b = b;
        }

        public string A
        {
            get
            {
                return a;
            }
        }

        public string B
        {
            get
            {
                return b;
            }
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            List<myobj> list = new List<myobj>();
            myobj[] objects = { new myobj("a", "b"), new myobj("c", "d"), new myobj("a", "b") };


            for (int i = 0; i < objects.Length; i++)
            {
                if (!list.Exists((delegate(myobj x) { return (string.Equals(x.A, objects[i].A) && string.Equals(x.B, objects[i].B)) ? true : false; })))
                {
                    list.Add(objects[i]);
                }
            }
        }
    }
}

楽しい!

3
Doug

シンプルだが機能する

MyList.Remove(nextObject)
MyList.Add(nextObject)

または

 if (!MyList.Contains(nextObject))
    MyList.Add(nextObject);
0
Opt Prutal