Junte-se à esquerda em duas listas e mantenha uma propriedade da direita com o Linq

Eu tenho 2 listas demesmo tipo. A lista da esquerda:

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});

E a lista certa:

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});

Eu quero fazer umaAssociação à esquerda, mas usando o valor noChanged propriedade dodireito. Como isso:

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

Para isso, não posso usar simplesAssociação à esquerdae não posso usar umConcat com o GroupBy.

Como posso fazer isso com o linq? Obrigado.

questionAnswers(4)

//Step 1: Merge the lists while selecting the matching objects from rightList using Last()
var mergedList = leftList.Concat(rightList)
 .GroupBy(x => x.Id)
 .Select(x => x.Last());

//Step 2: Do a inner join between mergedList and leftList to get a left join result as originally required.
var innerJoinQuery = from mPerson in mergedList
                     join leftPerson in leftList on mPerson.Id equals leftPerson.Id
                     select new { Id = leftPerson.Id, Name = mPerson.Name, Changed = mPerson.Changed };

gastador foi mais rápido que eu, fiz sem nenhum método de extensão.

Sem qualquer método de extensão:

List<Person> mergedList =  leftList
            .GroupJoin(
                rightList, left => left.Id, right => right.Id, 
                (x, y) => new { Left = x, Rights = y  }
            )
            .SelectMany(
                x => x.Rights.DefaultIfEmpty(),
                (x, y) => new Person
                {
                    Id = x.Left.Id, 
                    Name = x.Left.Name, 
                    Changed = y == null ? x.Left.Changed : y.Changed
                }
            ).ToList();

O GroupJoin faz operação de junção externa esquerda.

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();
QuestionSolution

Eu sempre mantenho esse método de extensão à mão para junções externas à esquerda, para que eu não precise procurar como usar a sintaxe desagradável de consulta (ou lembre-se de que é um GroupJoin) ...

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));
    }
}

Agora você pode:

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})
 Cameron MacFarland27 de nov de 2015 17:52
Você receberá um nullref na última linha. Alterado deve ser atribuídorgt == null ? lft.Changed : rgt.Changed
 spender27 de nov de 2015 21:22
@ RenanAraújo Hah! Está bem. O Recarregador praticamente escreveu para mim!
 Renan Araújo27 de nov de 2015 21:19
Oi gastador obrigado pela sua ajuda, desculpe pelo atraso, eu estava muito ocupado aqui. Boa extensão, obrigado por compartilhar!
 spender27 de nov de 2015 17:54
@CameronMacFarland: Ta!

yourAnswerToTheQuestion