web-dev-qa-db-ja.com

List <T>内の値を変更します

いくつかのリストがあります(Tはカスタムクラスで、クラスにはいくつかのプロパティがあります)。 Lambda Expressionsを使用して、1つ以上の値を変更する方法を知りたいので、結果はforeachループと同じになります。

注:リストには複数のアイテムが含まれています(複数行)

        foreach (MyClass mc in list)  
        {
            if (mc.Name == "height")
                mc.Value = 30;
        }

そして、これはlinqクエリ(Lambda式を使用)ですが、上部のforeachループとは異なり、リストから1アイテム(1行)のみを返します!

私が欲しいのは、すべてのアイテム(すべての行)を返し、適切なアイテム(WHERE拡張メソッドで指定されたアイテム)のみを変更することです。

list = list.Where(w => w.Name == "height").Select(s => { s.Value = 30; return s; }).ToList();

注:これら2つの例は同じではありません!繰り返しますが、linqは1つのアイテム(1行)のみを返しますが、これは望ましくありません。リストのすべてのアイテムも必要です(foreachループのように、変更のみを行いますが、アイテムは削除しません)。

47
Mitja Bonca

ForEach を使用できますが、最初にIEnumerable<T>List<T>に変換する必要があります。

list.Where(w => w.Name == "height").ToList().ForEach(s => s.Value = 30);
96
McGarnagle

私はおそらくこれで行くでしょう(純粋なlinqではないことを知っています)、すべてのアイテムを保持したい場合は元のリストへの参照を維持し、更新された値がそこにあることを見つける必要があります:

 foreach (var mc in list.Where(x => x.Name == "height"))  
     mc.Value = 30;
10
gmn

list.Find(x => x.Name == "height").Value = 20;はどうでしょうか。私はその古い投稿を知っていますが、なぜ誰もこれを提案していないのか疑問に思いましたか?このコードに欠点はありますか?

3
Aditya Muley

ステートメントlambdaでプロジェクションを使用できますが、元のforeachループは読みやすく、新しいリストを作成するのではなく、リストを所定の場所で編集しています。

var result = list.Select(i => 
   { 
      if (i.Name == "height") i.Value = 30;
      return i; 
   }).ToList();

拡張方法

public static IEnumerable<MyClass> SetHeights(
    this IEnumerable<MyClass> source, int value)
{
    foreach (var item in source)
    {
       if (item.Name == "height")
       {
           item.Value = value;
       }

       yield return item;
    } 
}

var result = list.SetHeights(30).ToList();
2
devdigital