List <T>で特定の要素を見つけるにはどうすればよいですか?


114

私のアプリケーションは次のようなリストを使用しています:

List<MyClass> list = new List<MyClass>();

を使用して Addメソッド、の別のインスタンスがMyClassリストに追加されます。

MyClass 特に、次のメソッドを提供します。

public void SetId(String Id);
public String GetId();

メソッドMyClassを使用しての特定のインスタンスを見つけるにはどうすればよいGetIdですか?私はFind方法があることを知っていますが、これがここで機能するかどうかわかりません!?

回答:


263

ラムダ式を使用する

MyClass result = list.Find(x => x.GetId() == "xy");

注:C#にはプロパティの組み込み構文があります。getterメソッドとsetterメソッドを(Javaから慣れているように)書く代わりに、

private string _id;
public string Id
{
    get
    {
        return _id;
    }
    set
    {
        _id = value;
    }
}

valueセットアクセサでのみ認識されるコンテキストキーワードです。プロパティに割り当てられた値を表します。

このパターンはよく使用されるため、C#は自動実装プロパティを提供し ます。これらは上記のコードの短いバージョンです。ただし、バッキング変数は非表示でアクセスできません(ただし、VBのクラス内からアクセスできます)。

public string Id { get; set; }

フィールドにアクセスしているかのように、プロパティを使用できます。

var obj = new MyClass();
obj.Id = "xy";       // Calls the setter with "xy" assigned to the value parameter.
string id = obj.Id;  // Calls the getter.

プロパティを使用して、このようなリスト内のアイテムを検索します

MyClass result = list.Find(x => x.Id == "xy"); 

読み取り専用プロパティが必要な場合は、自動実装プロパティを使用することもできます。

public string Id { get; private set; }

これによりId、クラスの内部を設定できますが、外部からは設定できません。派生クラスでも設定する必要がある場合は、セッターを保護することもできます

public string Id { get; protected set; }

最後に、プロパティをとして宣言virtualし、派生クラスでそれらをオーバーライドして、ゲッターとセッターに異なる実装を提供できます。通常の仮想メソッドと同じように。


C#6.0(Visual Studio 2015、Roslyn)以降、インライン初期化子を使用してゲッターのみの自動プロパティを記述できます

public string Id { get; } = "A07"; // Evaluated once when object is initialized.

代わりに、コンストラクタ内でゲッターのみのプロパティを初期化することもできます。ゲッターのみの自動プロパティは、プライベートセッターを使用して自動実装されるプロパティとは異なり、真の読み取り専用プロパティです。

これは、読み取り/書き込み自動プロパティでも機能します。

public string Id { get; set; } = "A07";

C#6.0以降では、プロパティを式本体のメンバーとして書き込むこともできます

public DateTime Yesterday => DateTime.Date.AddDays(-1); // Evaluated at each call.
// Instead of
public DateTime Yesterday { get { return DateTime.Date.AddDays(-1); } }

参照:.NETコンパイラプラットフォーム( "Roslyn")
          C#6の新しい言語機能

以降では、C#7.0、両方、ゲッターとセッター、表現体で書くことができます。

public string Name
{
    get => _name;                                // getter
    set => _name = value;                        // setter
}

この場合、セッターは式でなければならないことに注意してください。ステートメントにすることはできません。C#では代入を式またはステートメントとして使用できるため、上記の例は機能します。割り当て式の値は、割り当て自体が副作用である割り当て値です。これにより、一度に複数の変数に値を割り当てることができます。これは、ステートメントとx = y = z = 0同等でx = (y = (z = 0))あり、ステートメントと同じ効果がありx = 0; y = 0; z = 0;ます。

言語の次のバージョンであるC#9.0は、おそらく2020年11月に利用可能になりますが、オブジェクト初期化子で初期化できる読み取り専用(またはより優れた初期化1回)プロパティを許可します。現在、これはゲッターのみのプロパティでは不可能です。

public string Name { get; init; }

var c = new C { Name = "c-sharp" };

2
すばらしい答え、ありがとう。db操作のIQueryable<T> result = db.Set<T>().Find(//just id here//).ToList();場合は、次のようになります。主キーを探していることはすでにわかっています。参考までに。
ブロンド氏、2014年

これは古い答えであることはわかっていますが、比較中に誤って値が設定されないように、getメソッドとsetメソッドを別々のメソッドに分離します。
Joel Trauger

@JoelTrauger:比較はプロパティを読み取るため、ゲッターのみを呼び出します。
Olivier Jacot-Descombes

これは本当ですが、誤って割り当てるとセッターが呼び出され、プロパティが変更されます。参照return object.property = valuereturn object.property == value
ジョエルTrauger

別のsetメソッドを誤って呼び出すと、プロパティも変更されます。個別のget setメソッドがどのようにして安全性を向上させることができるかわかりません。
Olivier Jacot-Descombes 2016年

19
var list = new List<MyClass>();
var item = list.Find( x => x.GetId() == "TARGET_ID" );

または1つしかなく、あなたが望むものであるSingleOrDefaultかもしれないことを強制したい場合

var item = list.SingleOrDefault( x => x.GetId() == "TARGET" );

if ( item == null )
    throw new Exception();

例外をスローする必要がある場合に、singleOrDefaultを使用する理由は何ですか。Single()を使用します
コード名Jack


6

または、LINQを使用したくない場合は、昔ながらの方法で行うことができます。

List<MyClass> list = new List<MyClass>();
foreach (MyClass element in list)
{
    if (element.GetId() == "heres_where_you_put_what_you_are_looking_for")
    {

        break; // If you only want to find the first instance a break here would be best for your application
    }
}

4

LINQ拡張機能を使用することもできます。

string id = "hello";
MyClass result = list.Where(m => m.GetId() == id).First();

4
または、Firstの他のオーバーロード:MyClass result = list.First(m => m.GetId() == id);
Marcel Gosselin

3

匿名メソッド構文を使用して記述された述語を使用すると、問題を最も簡潔に解決できます。

MyClass found = list.Find(item => item.GetID() == ID);

0
public List<DealsCategory> DealCategory { get; set; }
int categoryid = Convert.ToInt16(dealsModel.DealCategory.Select(x => x.Id));

このコードで質問に答えることができますが、問題を解決する方法を説明し、例または参照としてコードを提供することをお勧めします。コードのみの回答は混乱を招き、コンテキストが不足する可能性があります。
ロバートコロンビア

0

検索条件を保持する検索変数を作成できます。これはデータベースを使用した例です。

 var query = from o in this.mJDBDataset.Products 
             where o.ProductStatus == textBox1.Text || o.Karrot == textBox1.Text 
             || o.ProductDetails == textBox1.Text || o.DepositDate == textBox1.Text 
             || o.SellDate == textBox1.Text
             select o;

 dataGridView1.DataSource = query.ToList();

 //Search and Calculate
 search = textBox1.Text;
 cnn.Open();
 string query1 = string.Format("select * from Products where ProductStatus='"
               + search +"'");
 SqlDataAdapter da = new SqlDataAdapter(query1, cnn);
 DataSet ds = new DataSet();
 da.Fill(ds, "Products");
 SqlDataReader reader;
 reader = new SqlCommand(query1, cnn).ExecuteReader();

 List<double> DuePayment = new List<double>();

 if (reader.HasRows)
 {

  while (reader.Read())
  {

   foreach (DataRow row in ds.Tables["Products"].Rows)
   {

     DuePaymentstring.Add(row["DuePayment"].ToString());
     DuePayment = DuePaymentstring.Select(x => double.Parse(x)).ToList();

   }
  }

  tdp = 0;
  tdp = DuePayment.Sum();                        
  DuePaymentstring.Remove(Convert.ToString(DuePaymentstring.Count));
  DuePayment.Clear();
 }
 cnn.Close();
 label3.Text = Convert.ToString(tdp + " Due Payment Count: " + 
 DuePayment.Count + " Due Payment string Count: " + DuePaymentstring.Count);
 tdp = 0;
 //DuePaymentstring.RemoveRange(0,DuePaymentstring.Count);
 //DuePayment.RemoveRange(0, DuePayment.Count);
 //Search and Calculate

ここで「var query」は、検索変数を通じて指定した検索基準を生成しています。次に、「DuePaymentstring.Select」は、指定された基準に一致するデータを選択しています。理解に問題があるかどうかお気軽にお尋ねください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.