5

I have problem with updating a single item under List<string> that matches a different string using LINQ. Let's say that I have a list of names and I want to check if name "John" already exists in my list. If yes, then replace "John" with "Anna".

Here is what I do:

var sItem = myList.First(n=> n == "John"); //I am 100% sure that John exists, that\s why I use .First
sItem = "Anna";

This is how it should work, but when I check my List (myList) after the process, the original item is still there (I can still see John, instead of Anna). I also tried to implement INotifyChanged on the List, but still no result.

What am I doing wrong?

Robert J.
  • 2,631
  • 8
  • 32
  • 59

6 Answers6

20

If you need to update, use FindIndex:

int index = myList.FindIndex(n => n == "John");
myList[index] = "Anna";
Lee
  • 142,018
  • 20
  • 234
  • 287
6

You are assigning the result of linq query to a string variable. That is not the element of list but a variable that is also referencing the element of that list. Changing the value of variable sItem will define a new string that will be referenced by the sItem and the item in the list remains unchanged.

You can use FindIndex to get the index of element in the array and use it to refer to list element.

int index = myList.FindIndex(n => n == "John");
myList[index] = "Anna";

Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the entire List.

Edit

When one string variable is assigned to other. They both would be referencing the same string but when you assign a different string to second variable for instance then they both referencing different strings. See the following example from answer of Eric Lippert.

a----------------------Hello

Then you say that "b = a", which means attach another piece of string to the same thing that a is attached to:

a----------------------Hello
                      /
b---------------------

Then you say "now attach b to Hi"

a----------------------Hello

b----------------------Hi
Community
  • 1
  • 1
Adil
  • 146,340
  • 25
  • 209
  • 204
  • Immutability of strings is not the reason why you cant change the list by assigning a different string to the variable. – Tim Schmelter Jul 30 '14 at 19:17
  • It has not to do anything with immutable. String is a reference type. The variable `n` in his example just reference the original string. If he assigns n to a new string then n just refers to a new object/string. Its the same as `var a = new SomeClass(); var b = a` if you now do `b = new SomeClass()` then you didn't change `a` at all, `b` now just reference a new object. – David Raab Jul 30 '14 at 19:20
  • @Adil: "because they are different objects" is still not the reason. They are the same objects, but the variable is different. Suppose we have two pieces of paper (variables). The same house address is written on both pieces of paper (that's the value of each variable, the reference). There's only one house (object). If someone writes a different address on one paper(reference to a diff. object) the other paper is not changed(the list). – Tim Schmelter Jul 30 '14 at 20:15
  • Thanks again for very good example and being so kind. I understand, how it works but probably the word object created the confusion. They are different references to the same object when they had same value (when result of query is assigned). I tried to explain it in a better way please have a look. – Adil Jul 30 '14 at 20:32
1
int index = strList.FindIndex(n => n == "John");
if (index != -1)
{
    strList[index] = "Anna";
}

This will ensure that if "John" does not exist in the list, the program does not crash.

Ankur
  • 11
  • 3
-1

It should work for you

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

list.Add("Gandarez");
list.Add("Carlos");

var search = list.FirstOrDefault(l => l == "Carlos");

if (search != null)
{
    var index = list.IndexOf("Carlos");
    list.RemoveAt(index);
    list.Insert(index, "Test");
}
gandarez
  • 2,609
  • 4
  • 34
  • 47
-1
int sItem = myList.FindIndex(x => x == "John");
myList[sItem] = "Anna";
Sherz
  • 1
-2

The problem you are seeing is that System.String, while actually a reference type, acts like a value type. So, when you assign a new value to sItem you are replacing it, not changing it.

If you were using a true reference type, what you tried could have worked:

List<Person> myList = ....;
var sItem = myList.First(p=> p.Name == "John");
sItem.Name = "Anna";

(Assigning -- sItem = new Person("Anna"); -- would still fail the same way,)

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • Actually it does not act as a value type, it acts like a reference type. If you have `var a = new SomeClass(5)` and you later do `a = new SomeClass(10)` then you also never changed the first object. `a` now just refers to a new object. It is the same with a string. `n = "John"` creates a new string that get assigned to the variable. And sure, that doesn't effect the string in his list at all, because it just hold a reference to its old string. – David Raab Jul 30 '14 at 19:16
  • @DavidRaab - It does act as a value type. It is a reference type that acts like a value type. – Enigmativity Aug 12 '21 at 05:25