TheDeveloper
TheDeveloper

Reputation: 1217

How to update an item in a list keeping the rest of the list intact through Linq

Say we have a list,

Dog d1 = new Dog("Fluffy", "1");
Dog d2 = new Dog("Rex", "2");
Dog d3 = new Dog("Luna", "3");
Dog d4 = new Dog("Willie", "4");

List<Dog> AllDogs = new List<Dog>()
AllDogs.Add(d1);
AllDogs.Add(d2);
AllDogs.Add(d3);
AllDogs.Add(d4);

If I want to update d4, from its name from willie to wolly. I want to return a list with all dogs with an update for d4.

I am trying something like this :

var dog = AllDogs.Where(d => d.Id == "2").FirstOrDefault();
if (dog != null) { dog.Name = "some value"; }

But this returns only the updated item, I want the whole list which includes the updated item.

Upvotes: 0

Views: 102

Answers (3)

Sehnsucht
Sehnsucht

Reputation: 5049

You could use List.ConvertAll which will do the same as a Linq Select and then a ToList (or some convoluted Aggregate).
It will create a whole new List with the same reference of the dog objects along with the modification made in the process :

// List.ConvertAll
var newAllDogs = allDogs.ConvertAll (dog => {
    if (dog.Id == 2)
        dog.Name = "some value";

    return dog;
});

// Linq version
var newAllDogs = allDogs.Select (dog => {
    if (dog.Id == 2)
        dog.Name = "some value";

    return dog;
}).ToList ();

But doing this kind of "side-effect mutation" (or List.ForEach which is even more "side-effecty") you should almost stick to classic "imperative" code using a foreach loop or List.Find :

// foreach
foreach (var dog in allDogs)
    if (dog.Id == 2)
    {
        dog.Name = "some value";
        break;
    }

// List.Find
var theDog = allDogs.Find (dog => dog.Id == 2);
theDog?.Name = "some value"; // using C#6 null conditional operator

// without null conditional operator
if (theDog != null)
    theDog.Name = "some value";

// in both cases allDogs will contain the updated dog

Upvotes: 1

user2023861
user2023861

Reputation: 8208

Here's the functional way to do it. This creates a new list with new dogs. This works with any IEnumerable<Dog>

var dogs = AllDogs.Select(s => 
  new Dog() { Id = s.Id, Name = (s.Id == "2" ? "some value" : s.Name) });

Here's a way to edit the list in place without creating any new objects. This works only with List<Dog>

AllDogs.ForEach(f => f.Name = (f.Id == "2" ? "some value" : f.Name));

Upvotes: 1

ChrisF
ChrisF

Reputation: 137178

AllDogs will contain the updated object, so all you need to do is make it a public property (if you are accessing it from another class) or a private class variable (if you are just accessing it with the same class).

The line:

var dog = AllDogs.Where(d => d.Id == "2").FirstOrDefault();

returns a reference to the object in the list so when you update it:

if (dog != null) { dog.Name = "some value"; }

you are updating it in the list.

Upvotes: 1

Related Questions