【问题标题】:Left join on two Lists and maintain one property from the right with Linq左连接两个列表并使用 Linq 从右侧维护一个属性
【发布时间】:2016-03-01 21:26:59
【问题描述】:

我有 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 做到这一点?谢谢。

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    这看起来像是一个非常标准的左外连接场景。

    我总是将此扩展方法方便地用于左外连接,因此我不必查找如何使用讨厌的查询语法(或记住 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})
    

    【讨论】:

    • 你会在最后一行得到一个 nullref。更改后应分配rgt == null ? lft.Changed : rgt.Changed
    • @CameronMacFarland:Ta!
    • 您好,感谢您的帮助,抱歉耽搁了,我在这里很忙。不错的扩展,谢谢分享!
    • @RenanAraújo 哈哈!没关系。 Resharper 几乎是为我写的!
    【解决方案2】:

    为什么不试试这样的解决方案:

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

    【讨论】:

      【解决方案3】:

      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 进行左外连接操作。

      【讨论】:

        【解决方案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 };
        

        【讨论】:

          猜你喜欢
          • 2015-08-26
          • 2021-12-28
          • 2021-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多