21

I have a list which I want to update using 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));

Now I want to update the list using LINQ such that only marks of John gets updated. I am using the following syntax:

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

But this doesnt update data in myList. Can someone tell me where am I going wrong.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
user3625024
  • 319
  • 1
  • 2
  • 11
  • 8
    `LINQ` is used for querying data not updating. Better to do it using a `foreach` loop. – Rahul Singh May 05 '15 at 14:24
  • I tried foreach(item in myList.where(w => w.Name == "Tom")) { item.Marks = 35; } but get an error - cannot modify members of 'item' because it is a 'foreach iteration variable' – user3625024 May 05 '15 at 14:28
  • 1
    Your code as posted does not compile - missing parens, mismatched data types, inconsistent capitalization, hiding of fields in constructor, etc. If you post something that is closer to your original code and _actually compiles_ then the problem may be apparent. As it stands a simple `foreach` after your query should work. – D Stanley May 05 '15 at 14:45
  • 2
    The code you claim generates the 'cannot modify members of 'item'' does not. It would generate this if `Student` was a `struct` rather than a `class`. The sample code you provide doesn't compile. Can you provide the *actual* code you're using? – Charles Mager May 05 '15 at 14:46

10 Answers10

46

LINQ is for querying, not for updating the data. Use LINQ to get the items that you want to modify, and then modify them in a foreach loop:

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

Demo.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
20

Try:

myList .Where(w=> w.Name  == "dTomi").ToList().ForEach(i => i.Marks  = 35);
Al Foиce ѫ
  • 4,195
  • 12
  • 39
  • 49
SHIBIN
  • 397
  • 3
  • 5
  • 3
    This doesn't explain anything, while OP is asking what they're doing wrong. Code-only answers are far more valuable when they also contain an explanation. – Gert Arnold Apr 02 '17 at 12:18
11

Select(), like any other LINQ method, doesn't change a source collection, instead, it return a new collection.

So you should either assign that new collection to myList:

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

or assign Marks property in a separate foreach loop

myList.Where(w => w.Name == "Tom").ToList().ForEach(w => w.Marks = 35);
Prayag
  • 422
  • 3
  • 9
  • 1
    Welcome to Stack Overflow! While this code snippet may be the solution, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Kurt Van den Branden Nov 16 '18 at 12:33
  • @KurtVandenBranden though its an old post, but you mean to say readers in future wont be able to read the question to understand why this code suggestion is here? Because I read all answers and understood all of them, despite being few of them are without explanation. – GKG4 Aug 22 '20 at 06:06
10

As others have pointed out, LINQ is for querying data, it is not for doing updates.

You should iterate your list, and modify your values like:

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

Or

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

Whatever you think better conveys the intent use that.


but here is an interesting thing:

If you have a statement like:

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

Without assigning the result back to myList the above query will modify the value in the original list. Remember, it is a side effect and it is not the proper way to update. This is modification can be explained by reference parameter being passed to a method and getting modified there. But Importantly, this should always be avoided. It is a bad practice and could lead to really confusing code. Use LINQ for querying only.

Habib
  • 219,104
  • 29
  • 407
  • 436
  • 3
    +1 This points out an important point that was driving me nuts since many posts supply your anti-pattern as the answer and I was wondering if I understood the Q in LINQ properly. Thanks :-) – GGleGrand May 18 '16 at 13:07
  • See this post for more: http://stackoverflow.com/questions/1776387/using-linq-to-update-a-property-in-a-list-of-entities – GGleGrand May 18 '16 at 13:16
3

Above can be achieved by just assign the value back to the collection

myList = myList
        .Where(w => w.Name == "Tom")
        .Select(w=> { w.Marks = 35; return w})
        .ToList();
Sathish
  • 2,029
  • 15
  • 13
0

how about old good for loop

for(int i = 0; i < myList.Count; i++)
if (myList[i].Name  == "Tom")
{
    myList[i].Marks = 35;
    break;
}
ASh
  • 34,632
  • 9
  • 60
  • 82
0

well @dasblinkenlight code should work but you can also try something like this

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

This is kind of clunky, but works, and doesn't depend on being passed a reference. It creates a new list based on the old.

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

Or more silly:

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

Objects are stored by reference in the list so you can recover object via linq and then edit, it will be reflect the changes on the list.

Example

    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; }
    }

Testing the app you will get the follow result:

First text value:Text2

Edited text value:Hello You!!

Community
  • 1
  • 1
0

List can be updated with linq as sample code below, to avoid iteration :

        if (resultQuiz.ANSWER_Q != null) {
            questionsvm.Where(x => x.QUESTION_ID == resultQuiz.QUESTION_ID).FirstOrDefault().ANSWER_Q = resultQuiz.ANSWER_Q;

            questionsvm.Where(x => x.QUESTION_ID == resultQuiz.QUESTION_ID).FirstOrDefault().ISCORRECT =
                questionsvm.Where(x => x.QUESTION_ID == resultQuiz.QUESTION_ID).FirstOrDefault().ANSWER_TEXT.ToLower() == resultQuiz.ANSWER_Q.ToLower();             
        }