Update list of items in c#

1.9k views Asked by At

I would like to know if you can suggest me an efficient way to update a list of items in c#. Here is a generic example:

If CurrentList is

[ {Id: 154, Name: "George", Salary: 10 000}
  {Id: 233, Name: "Alice", Salary: 10 000}]

And NewList is

[ {Id: 154, Name: "George", Salary: 25 000}
  {Id: 234, Name: "Bob", Salary: 10 000}]

Then the result should be:

[{Id: 154, Name: "George", Salary: 25 000} 
{Id: 234, Name: "Bob", Salary: 10 000} ]

I don't want just to clear the first one and use the values from the second one, but want to update the ones with the same ID, remove the ones that have been deleted and add any new ones.

Thanks in advance.

3

There are 3 answers

0
Jeroen van Langen On BEST ANSWER

I would do something like this: (for ordinairy lists)

// the current list
var currentList = new List<Employee>();
currentList.Add(new Employee { Id = 154, Name = "George", Salary = 10000 });
currentList.Add(new Employee { Id = 233, Name = "Alice", Salary = 10000 });

// new list
var newList = new List<Employee>();
newList.Add(new Employee { Id = 154, Name = "George", Salary = 25000 });
newList.Add(new Employee { Id = 234, Name = "Bob", Salary = 10000 });

// clean up
foreach (var oldEmployee in currentList.ToArray())
    if (!newList.Any(item => oldEmployee.Id == item.Id))
        currentList.Remove(oldEmployee);

// check if the new item is found within the currentlist. 
// If so? update it's values else add the object.
foreach (var newEmployee in newList)
{
    var oldEmployee = currentList.FirstOrDefault(item => item.Id == newEmployee.Id);
    if (oldEmployee == null)
    {
        // add
        currentList.Add(newEmployee);
    }
    else
    {
        // modify
        oldEmployee.Name = newEmployee.Name;
        oldEmployee.Salary = newEmployee.Salary;
    }
}

You can speed it up, using dictionaries, but that's not your question (for now)

0
Chris Lee On

A LINQ'y version wrapped in an extension method, could modified to be generic if 'Id' is on a interface of some sort.

The merge Action could potentially be a Merge() method on entity objects such as employee but I chose to use a delegate here .

public class Tests
{
    [Test]
    public void MergeSpike()
    {
        // the current list
        var currentList = new List<Employee>();
        currentList.Add(new Employee { Id = 154, Name = "George", Salary = 10000 });
        currentList.Add(new Employee { Id = 233, Name = "Alice", Salary = 10000 });

        // new list
        var newList = new List<Employee>();
        newList.Add(new Employee { Id = 154, Name = "George", Salary = 25000 });
        newList.Add(new Employee { Id = 234, Name = "Bob", Salary = 30000 });

        currentList.Merge(newList, (o, n) =>
        {
            if(o.Id != n.Id) throw new ArgumentOutOfRangeException("Attempt to merge on mismatched IDs");
            o.Name = n.Name;
            o.Salary = n.Salary;
        });


        Assert.That(currentList.Count(), Is.EqualTo(2));
        Assert.That(currentList.First(c => c.Id == 154).Salary, Is.EqualTo(25000));
        Assert.That(currentList.Any(c => c.Id == 233), Is.False);
        Assert.That(currentList.First(c => c.Id == 234).Salary, Is.EqualTo(30000));


    }
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Salary { get; set; }
}

public static class EmployeeListExtensions
{
    public static void Merge(this List<Employee> currentList, IEnumerable<Employee> newList, Action<Employee, Employee> merge)
    {
        // Updates
        currentList.Where(e => newList.Any(n => n.Id == e.Id))
            .ToList().ForEach(e => merge(e, newList.First(n1 => n1.Id == e.Id)));

        // Deletes
        var remove = currentList.Where(cl => newList.All(nl => cl.Id != nl.Id)).ToList();
        currentList.RemoveAll(e => remove.Any(r => r.Id == e.Id));

        // Inserts
        currentList.AddRange(newList.Where(nl => currentList.Any(c => c.Id != nl.Id)));
    }
}
2
Fabjan On

You can do it with use of for loop and Linq expression:

        for (int i = 0; i < NewList.Count; i++)
        {
            var record = CurrentList.FirstOrDefault(item => item.Id == NewList[i].Id);
            if (record == null) { CurrentList.Add(NewList[i]); }
            else { record.Id = NewList[i].Id; record.Name = NewList[i].Name; record.Salary = NewList[i].Salary; }
        }

        CurrentList.RemoveAll(item => NewList.FirstOrDefault(item2 => item2.Id == item.Id) == null);

Example of usage: Example