Elisabeth
Elisabeth

Reputation: 21206

Merge equal items with multiple lists but different length

I have 2 lists.

They are different in length but same type.

I want that an Item from List2 replaces an equal item in List1.

var item1 = new Item { Id = 1, Name = "Test1" };
var item2 = new Item { Id = 2, Name = "Test2" };
var item3 = new Item { Id = 3, Name = "Test3" };
var item4 = new Item { Id = 4, Name = "Test4" };
var item5 = new Item { Id = 5, Name = "Test5" };

var list1 = new List<Item> { item1, item2, item3, item4, item5 };
var list2 = new List<Item> { new Item { Id = 1, Name = "NewValue" } };

As a result I expect a list with 5 items where the item with Id = 1 has a value "NewValue".

How can I do that preferable with linq.

UPDATE

I extend my question:

How can the replacement of the replaced Item happen without copying all properties manually. Just imagine I have 100 properties...

Upvotes: 3

Views: 114

Answers (3)

jhmt
jhmt

Reputation: 1421

I think LEFT OUTER JOIN in Linq will be able to merge 2 lists regardless of number of properties(columns) like this:

    List<Item> newItems =
        (from l1 in list1
         join l2 in list2 on l1.Id equals l2.Id into l12
         from l2 in l12.DefaultIfEmpty()
         select new { Item = (l2 == null) ? l1 : l2 }).Select(r => r.Item).ToList();

Upvotes: 1

kkyr
kkyr

Reputation: 3845

Off the top of my head this is one solution

var list3 = new List<Item>();    

foreach (var item in list1)   
   list3.Add(list2.FirstOrDefault(s => s.Id == item.Id) ?? item);

Upvotes: 1

Yacoub Massad
Yacoub Massad

Reputation: 27861

This is one way to do it:

First define an equality comparer that depends only on the Id property of the Item class like this:

public class IdBasedItemEqualityComparer : IEqualityComparer<Item>
{
    public bool Equals(Item x, Item y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Item obj)
    {
        return obj.Id.GetHashCode();
    }
}

Then you can take items list1 that don't have corresponding items in list2 using the Except method and then you can concatenate that with list2 using the Concat method like this:

var result = list1.Except(list2, new IdBasedItemEqualityComparer()).Concat(list2).ToList();

Notice how I use the IdBasedItemEqualityComparer with the Except method, so that comparison is based only on Id.

Upvotes: 3

Related Questions