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


102

リストがあります

  List<MyObject> myList

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

これを行う前に:

 myList.Add(nextObject);

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

オブジェクト「MyObject」にはいくつかのプロパティがありますが、比較は2つのプロパティのマッチングに基づいています。

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

私が考えた唯一の解決策は、リストからディクショナリに変更してから、キーをプロパティの連結された文字列にすることです(これは少し見苦しいようです)。

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

回答:


153

特定の状況のニーズによって異なります。たとえば、ディクショナリアプローチは次のように想定すると非常に適切です。

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

上記があなたの状況に当てはまらない場合は、メソッドを使用してくださいAny()

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

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


list.existsに述語デリゲートを使用することは、以下の別の解決策ですが、巨大なリストがあり、ディクショナリのキー値がある場合、ハッシュテーブルであるため、はるかに高速になります。楽しむ
ダグ

1
複数の値を確認する方法は?
Nitin Karale

80

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

bool alreadyExist = list.Contains(item);

5
これは私にとってはうまく
いき

4
@ Si8オブジェクトを比較する場合は、IEquatable <T> .Equals実装がオブジェクトのタイプに適切に実装されていることを確認する必要があります。それ以外の場合は、オブジェクトの内容を比較しません。これを実装する方法の例については、Ahmadに示されている「Contains」リンクを参照してください。
Doug Knudsen 2017

56

これらの2つのプロパティを使用することが維持可能であれば、次のことができます。

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

7

この場合、リストが必要ですか?リストに多くのアイテムを入力している場合、パフォーマンスは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実装を作成する必要はありません。あなただけオーバーライドすることができますGetHashCodeし、Equalsクラス自体インチ


はい、Vのboolは私のお気に入りでした。さらに言えば、私が2.0コードに取り組んでいたためにHashSetが利用できなくなったのはそれほど前のことではありません(ええと、約3週間)。
Jon Hanna

4

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

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


3

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

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

編集:私は最初に言っていました:


辞書ソリューションについて何が優雅ではないのか。特に、辞書を作成するときにコンパレータを設定するだけでよいので、私には完全にエレガントに思えます。


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

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


ハッシュテーブルでオブジェクトのリストが膨大で、高速な検索に最適な場合にのみ、これを使用します。
Doug

0

シンプルですが動作します

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

または

 if (!MyList.Contains(nextObject))
    MyList.Add(nextObject);

-1

EFコアを使用する場合は追加

 .UseSerialColumn();

modelBuilder.Entity<JobItem>(entity =>
        {
            entity.ToTable("jobs");

            entity.Property(e => e.Id)
                .HasColumnName("id")
                .UseSerialColumn();
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.