web-dev-qa-db-ja.com

LINQを使用してリストの値を更新する方法

LINQを使用して更新したいリストがあります。

class Student
{
    private string name;
    private int marks;
    public string Name { get; set;}
    public int Marks { get; set; }
    public Student(string name, int marks)
    {
        Name = name;
        Marks = marks;
    }
}

List<Student> myList = new List<Student>();
myList.Add(new Student("John", 10));
myList.Add(new Student("Tom", 20));

次に、Johnのマークだけが更新されるように、LINQを使用してリストを更新します。次の構文を使用しています。

myList.Where(w => w.Name == "Tom").Select(w=> { w.Marks = 35; return w});

しかし、これはmyListのデータを更新しません。誰かがどこで間違っているのか教えてもらえますか?.

6
user3625024

LINQはクエリ用であり、データの更新用ではありません。 LINQを使用して変更するアイテムを取得し、foreachループでそれらを変更します。

foreach ( var tom in myList.Where(w => w.Name == "Tom")) {
    tom.Marks = 35;
}

デモ

22
dasblinkenlight

他の人が指摘したように、LINQはデータをクエリするためのものであり、更新を行うためのものではありません。

リストを反復して、次のように値を変更する必要があります。

foreach (var student in myList)
{
    if (student.Name == "Tom")
    {
        student.Marks = 35;
    }
}

または

foreach (var student in myList.Where(r => r.Name == "Tom"))
{
    student.Marks = 35;
}

あなたがより良いと思うものは何でもそれを使用する意図を伝えます。


しかし、ここに興味深いものがあります:

次のようなステートメントがある場合:

myList.Where(w => w.Name == "Tom").Select(w => w.Marks = 35).ToList();

結果をmyListに割り当てない場合、上記のクエリは元のリストの値を変更します。 覚えておいてください、これは副作用であり、proper更新する方法ではありません。これは、参照パラメーターがメソッドに渡されてそこで変更されることで説明できます。 しかし重要なことに、これは常に避けられるべきです。これは悪い習慣であり、コードを本当に混乱させる可能性があります。クエリのみにLINQを使用します。

5
Habib

試してください:

myList .Where(w=> w.Name  == "dTomi").ToList().ForEach(i => i.Marks  = 35);
2
SHIBIN

上記は、コレクションに値を割り当てるだけで実現できます。

myList = myList
        .Where(w => w.Name == "Tom")
        .Select(w=> { w.Marks = 35; return w})
        .ToList();
1
Sathish

オブジェクトは参照によってリストに保存されるので、linqを介してオブジェクトを回復してから編集でき、リストの変更が反映されます。

    static void Main(string[] args)
        {
            List<Entity> testList = new List<Entity>()
            {
                new Entity() {Id = 1, Text = "Text"},
                new Entity() {Id = 2, Text = "Text2"}
            };

            Console.WriteLine($"First text value:{testList[1].Text}");

            Entity entityToEdit = testList.FirstOrDefault(e => e.Id == 2);
            if (entityToEdit != null)
                entityToEdit.Text = "Hello You!!";

            Console.WriteLine($"Edited text value:{testList[1].Text}");

            Console.ReadLine();
        }

 internal class Entity
    {
        public int Id { get; set; }
        public String Text { get; set; }
    }

アプリをテストすると、次の結果が得られます。

最初のテキスト値:Text2

編集されたテキスト値:Hello You !!

0
Final Nemael

古き良きforループはどうですか

for(int i = 0; i < myList.Count; i++)
if (myList[i].Name  == "Tom")
{
    myList[i].Marks = 35;
    break;
}
0
ASh

よく@dasblinkenlightコードは動作するはずですが、このようなものを試すこともできます

 var query = from x in list
             where x.Name = yourcondition
             select new { x };
foreach(var item in query)
   item.x.FieldToUpdate = SetValue;
0
user2726374

これはちょっと不格好ですが、機能し、参照が渡されることに依存しません。古いものに基づいて新しいリストを作成します。

var myList=myList.Select(l=>new Student { 
   l.Name,
   Marks=l.Name=="Tom"?35:l.Marks}).ToList();

またはもっとばかげた:

var myList=myList.Where(l=>l.Name!="Tom").Union(
  myList.Where(l=>l.Name=="Tom").Select(l=>new Student { 
   l.Name,
   Marks=35})).ToList();
0
Robert McKee