Replace a object in a list of objects

C#.NetListVariable AssignmentGeneric List

C# Problem Overview


In C#, if I have a List<T>, and I have an object of type T, how can I replace a specific item in the List<T> with the object of type T?

Here is what I have tried:

List<CustomListItem> customListItems = new List<CustomListItem>();
CustomListItem customListItem1 = new CustomListItem() { name = "Item 1", date = DateTime.MinValue};
CustomListItem customListItem2 = new CustomListItem() { name = "Item 2", date = DateTime.MinValue };
CustomListItem customListItem3 = new CustomListItem() { name = "Item 3", date = DateTime.MinValue };

customListItems.Add(customListItem1);
customListItems.Add(customListItem2);
customListItems.Add(customListItem3);

CustomListItem newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();
customListItem2 = newCustomListItem;

In the above code, I want to replace the customListItem2 with the newCustomListItem.

Do I have to remove the item in the list, and then insert the new item? Can I not do a simple assignment of customListItem2 = newCustomListItem?

What is the most efficient way of replacing an item in a list with another item?

Thanks in advance

C# Solutions


Solution 1 - C#

You have to replace the item, not the value of customListItem2. Just replace following:

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();
customListItem2 = newCustomListItem;

With this:

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();
var index = customListItems.IndexOf(customListItem2);

if(index != -1)
    customListItems[index] = newCustomListItem;

Edit:

As Roman R. stated in a comment, you can replace the .Where(predicate).First() by a simple First(predicate):

customListItem2 = customListItems.First(i=> i.name == "Item 2");

Solution 2 - C#

var customListItems = new List<CustomListItem>();
var customListItem1 = new CustomListItem() { name = "Item 1", date = DateTime.MinValue };
var customListItem2 = new CustomListItem() { name = "Item 2", date = DateTime.MinValue };
var customListItem3 = new CustomListItem() { name = "Item 3", date = DateTime.MinValue };

customListItems.Add(customListItem1);
customListItems.Add(customListItem2);
customListItems.Add(customListItem3);

var newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

customListItems[customListItems.FindIndex(x => x.name == "Item 2")] = newCustomListItem;

or

public static class ListExtensions
{
    public static void Replace<T>(this List<T> list, Predicate<T> oldItemSelector , T newItem)
    {
        //check for different situations here and throw exception
        //if list contains multiple items that match the predicate
        //or check for nullability of list and etc ...
        var oldItemIndex = list.FindIndex(oldItemSelector);
        list[oldItemIndex] = newItem;
    }
}

and then

customListItems.Replace(x => x.name == "Item 2", newCustomListItem);

Solution 3 - C#

if sequence of list not matter to you then you can try this

CustomListItem newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();  

customListItems.Remove(customListItem2);
customListItems.Add(newCustomListItem );

Solution 4 - C#

You can use a select to build a new iEnumerable with replace item :

customListItems.Select(x => x.name == "Item 2" ? newItem : x).ToList();

i did not test for performance but I found this solution quite concise and explicit.

Solution 5 - C#

An alternative would be to use the DynamicData package that has lot of others facilities on lists:

Quick Answer

make sure the package is installed:

Install-Package DynamicData -Version 7.4.3

then

using DynamicData;

DynamicData.ListEx.Replace<CustomListItem>(customListItems, customListItem2, newCustomListItem);

The following is the complete working solution.

Working Example

my custom item class

public class CustomListItem
{
    public string name; 
    public DateTime date;

    public override string ToString()
    {
        return name + ", " + date.ToString();
    }
}

In the main try this, make sure to comment out the assignment before the replacement.

static void Main(string[] args)
{
    List<CustomListItem> customListItems = new List<CustomListItem>();
    CustomListItem customListItem1 = new CustomListItem() { name = "Item 1", date = DateTime.MinValue };
    CustomListItem customListItem2 = new CustomListItem() { name = "Item 2", date = DateTime.MinValue };
    CustomListItem customListItem3 = new CustomListItem() { name = "Item 3", date = DateTime.MinValue };

    customListItems.Add(customListItem1);
    customListItems.Add(customListItem2);
    customListItems.Add(customListItem3);

    CustomListItem newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

    customListItem2 = customListItems.Where(i => i.name == "Item 2").First();
    //customListItem2 = newCustomListItem;


    DynamicData.ListEx.Replace<CustomListItem>(customListItems, customListItem2, newCustomListItem);

    foreach(var customListItem in customListItems)
    {
        Debug.Print("\n" + customListItem.ToString());
    }
}

references: https://github.com/reactivemarbles/DynamicData.
https://dynamic-data.org

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3736648View Question on Stackoverflow
Solution 1 - C#AbbasView Answer on Stackoverflow
Solution 2 - C#Hamid PourjamView Answer on Stackoverflow
Solution 3 - C#user4093832View Answer on Stackoverflow
Solution 4 - C#Olivier DuhartView Answer on Stackoverflow
Solution 5 - C#OliamsterView Answer on Stackoverflow