我有2个相同类型的列表。左侧列表:
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});
正确的清单:
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});
我想要左连接,但是使用右侧的Changed
属性上的值。像这样:
{Id = 1, Name = "John", Changed = false}
{Id = 2, Name = "Alice", Changed = false}
{Id = 3, Name = "Mike", Changed = true} // <-- true from the rightList
为此,我无法使用简单的Left Join,也无法使用Concat with GroupBy。
如何使用linq执行此操作?感谢。
答案 0 :(得分:9)
这看起来像一个非常标准的左外连接场景。
我总是将此扩展方法保留为左外连接方便,所以我不必查看如何使用讨厌的查询语法(或者记住wtf一个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));
}
}
现在你可以:
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 :(得分:3)
为什么不尝试这样的解决方案:
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();
答案 2 :(得分:1)
另一种方法是:
//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 };
答案 3 :(得分:1)
好spender比我快,我没有任何扩展方法。
没有任何扩展方法:
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();
GroupJoin进行左外连接操作。