Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Left join on two Lists and maintain one property from the right with Linq

Tags:

c#

linq

I have 2 lists of the same type. The left list:

var leftList = new List<Person>();
leftList.Add(new Person {Id = 1, Name = "John", Changed = false});
leftList.Add(new Person {Id = 2, Name = "Alice", Changed = false});
leftList.Add(new Person {Id = 3, Name = "Mike", Changed = false});

And the right list:

var rightList = new List<Person>();
rightList.Add(new Person {Id = 1, Name = "John", Changed = false});
rightList.Add(new Person {Id = 3, Name = "Mike", Changed = true});
rightList.Add(new Person {Id = 4, Name = "Joshi", Changed = true});

I want to do a left join, but using the value on the Changed property from the right. Like this:

{Id = 1, Name = "John", Changed = false}
{Id = 2, Name = "Alice", Changed = false}
{Id = 3, Name = "Mike", Changed = true} // <-- true from the rightList

For this, I can't use simple Left Join, and I cannot use a Concat with GroupBy.

How can I do this with linq? Thanks.

like image 922
Renan Araújo Avatar asked Nov 27 '15 16:11

Renan Araújo


People also ask

Can we use left join in LINQ?

You can use LINQ to perform a left outer join by calling the DefaultIfEmpty method on the results of a group join.

How Use left and right join in LINQ?

In LINQ, LEFT JOIN or LEFT OUTER JOIN is used to return all the records or elements from the left side collection and matching the elements from the right side of the collection. In LINQ, to achieve the LEFT Join behavior, it is mandatory to use the "INTO" keyword and "DefaultfEmpty()" method.

Can we use joins in LINQ?

relational tables. In a LINQ query expression, join operations are performed on object collections. Object collections cannot be "joined" in exactly the same way as two relational tables.

What is Groupjoin in LINQ?

The group join is useful for producing hierarchical data structures. It pairs each element from the first collection with a set of correlated elements from the second collection. For example, a class or a relational database table named Student might contain two fields: Id and Name .


2 Answers

This looks like a pretty standard left outer join scenario.

I always keep this extension method handy for left outer joins so I don't have to look up how to use the nasty query syntax (or remember wtf a GroupJoin is)...

public static class LinqEx
{
    public static IEnumerable<TResult> LeftOuterJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer, 
        IEnumerable<TInner> inner, 
        Func<TOuter, TKey> outerKeySelector, 
        Func<TInner, TKey> innerKeySelector, 
        Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer
            .GroupJoin(inner, outerKeySelector, innerKeySelector, (a, b) => new
            {
                a,
                b
            })
            .SelectMany(x => x.b.DefaultIfEmpty(), (x, b) => resultSelector(x.a, b));
    }
}

Now you can:

leftList.LeftOuterJoin(
     rightList, 
     lft => lft.Id,
     rgt => rgt.Id,
     (lft, rgt) => new Person{Id = lft.Id, 
                              Name = lft.Name, 
                              Changed = rgt == null ? lft.Changed : rgt.Changed})
like image 54
spender Avatar answered Nov 15 '22 13:11

spender


Why don't you try a solution like this:

var query = (from left in leftList
    join right in rightList on left.Id equals right.Id into joinedList
    from sub in joinedList.DefaultIfEmpty()
    select new Person { 
        Id = left.Id,
        Name = left.Name,
        Changed = sub == null ? left.Changed : sub.Changed }).ToList();
like image 28
user449689 Avatar answered Nov 15 '22 14:11

user449689