2015-11-27 2 views
7

Ich habe 2 Listen der gleichen Typs. Die linke Liste:Linke beitreten auf zwei Listen und pflegen eine Eigenschaft von rechts mit Linq

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

Und die richtige Liste:

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

Ich möchte beitreten ein mehr tun, aber den Wert auf der Changed Eigenschaft aus der rechts verwenden. Wie folgt aus:

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

Dazu kann ich nicht einfach verwenden Left Join, und ich kann nicht einen Concat with GroupBy verwenden.

Wie kann ich das mit Linq? Vielen Dank.

Antwort

6

Dies sieht wie ein ziemlich normales linkes Outer-Join-Szenario aus.

ich diese Erweiterung Methode immer halten praktisch für linke Outer-Joins, damit ich nicht sehen, wie die fiese Abfragesyntax zu verwenden (oder erinnern wtf ein GroupJoin ist) ...

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

Jetzt Sie können:

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}) 
+1

Sie erhalten einen Nullref in der letzten Zeile. Geändert sollte zugewiesen werden 'rgt == null? lft.Changed: rgt.Changed' –

+0

@CameronMacFarland: Ta! – spender

+0

Hallo Spender danke für deine Hilfe, sorry wegen der Verspätung, ich war sehr beschäftigt hier. Schöne Erweiterung, vielen Dank für das Teilen! –

3

Warum Sie nicht über eine Lösung wie diese versuchen:

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

eine andere Möglichkeit, es zu tun wäre:

1

Nun spender war schneller als ich, ich habe ohne Erweiterung Methode.

Ohne Erweiterungsmethode:

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

Die GroupJoin macht linke äußere Betrieb verbinden.