Search code examples
c#linqmorelinq

How to compare and merge lists using linq or moreLinq


I have two lists of type KeyValuePair.

Values are as following

List A
2019-01-01 1
2019-01-02 0
2019-01-03 1

List B
2019-01-01 0
2019-01-03 1

I want to merge these two list so it looks like this

List C 

2019-01-01 0 //item from list B 
2019-01-02 0 //item from list A, missing date in List B
2019-01-03 1 //item from list A - items are the same in list A and B

Is there a way with Linq or MoreLinq that can actually do this, ie.

  • merge items from two lists
  • use item from list A if same item does not exist in list B
  • replace item from list A with item from list B if they are not equal

Solution

  • If you know you can never have a default DateTime as the key:

    var r = from a in ListA
    join b in ListB on a.Key equals b.Key into joined
    from b in joined.DefaultIfEmpty()
    select b.Key != default(DateTime) ? b : a;
    

    If you might have a default DateTime then convert the keys to a DateTime? and back again to detect the missing case reliably:

    var r = from a in ListA.Select(kv => new KeyValuePair<DateTime?, int>(kv.Key, kv.Value))
    join b in ListB.Select(kv => new KeyValuePair<DateTime?, int>(kv.Key, kv.Value))
    on a.Key equals b.Key into joined
    from b in joined.DefaultIfEmpty()
    select new KeyValuePair<DateTime, int>(b.Key ?? a.Key.GetValueOrDefault(), b.Value);
    

    Note that in both we skip the rule "replace item from list A with item from list B if they are not equal" with just "use the item from B if it exists" because we have to check if B exists anyway, and if B's value is the same as A's then it doesn't matter that we still used it.

    I'd probably just build a dictionary from A and then replace the values with those from B unless I really cared about order, though.