【问题标题】:Does C# linq support "anti join" semantics?C# linq 是否支持“反连接”语义?
【发布时间】:2019-07-26 09:28:43
【问题描述】:

我用谷歌搜索了一会儿,没有找到直接的反连接语义示例。以 C# LINQ 为例,如何做到这一点?

【问题讨论】:

  • 反连接是左连接,右键为空?那么你就有答案了
  • 如果 MoreLinq 是一个选项,请使用 ExceptBy

标签: c# linq join anti-join


【解决方案1】:

反连接基本上是一组不包含在另一组中的数据,可以在Linq 中用IEnumerable.Except 表示,如下所示:

double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.2 };

IEnumerable<double> onlyInFirstSet = numbers1.Except(numbers2);

foreach (double number in onlyInFirstSet)
    Console.WriteLine(number);

这当然需要为自定义类定义IEqualityComparer

使用where 的另一种语法是:

var antiJoin = numbers1.Where(number => !numbers2.Contains(number));

在 Microsoft 文档上阅读 Enumerable.Except Method 的更多信息。

编辑:

至于“db 驱动的 linq”,这是一个适用于 Entity Framework 的示例,使用 Except


var filteredProducts = db.Products.ToList()
    .Except(db.Orders.Where(o => o.OrderId = 123)
        .Select(o => o.Product).ToList())
    .ToList();

至于where 替代方案:

var filterProducts = db.Orders.Where(o => o.OrderId = 123)
    .Select(o => o.Product).ToList();
var antiJoinProducts = db.Products.Where(p => !filterProducts.Contains(p));

【讨论】:

    【解决方案2】:

    假设这与您之前的问题有关 -

    如果您想在查询中包含您找不到部门的员工(基本上是left outer join),您可以这样做:

    var result = from e in employees
                     join d in departments on e.DeptId equals d.DeptId into gj
                     from subdept in gj.DefaultIfEmpty()
                     select new { e.EmpName, subdept?.DeptName };
    

    如果您只想检索无法匹配部门的员工(我猜那将是您的anti join),那么您只需添加一个subdept is null 像这样的条件:

    var result = from e in employees
                     join d in departments on e.DeptId equals d.DeptId into gj
                     from subdept in gj.DefaultIfEmpty()
                     where subdept is null
                     select new { e.EmpName, subdept?.DeptName };
    

    有关 C# Linq 中 left outer joins 的更多信息,您可以查看 this

    【讨论】:

      【解决方案3】:

      我认为没有直接的方法可以实现这一点,但是通过几个扩展方法很容易。

      设置:

      public class Class1
      {
        public int Id;
        public string Info;
      }
      
      public class Class2
      {
        public int Id;
        public string Data;
      }
      

      用法:

      List<Class1> l1 = new List<Class1>() { new Class1() { Id = 1, Info = "abc" }, new Class1() { Id = 2, Info = "123" } };
      List<Class2> l2 = new List<Class2>() { new Class2() { Id = 2, Data = "dsfg" }, new Class2() { Id = 3, Data = "asdfsaf" } };
      
      l1 = l1.Where(c1 => ! l2.Select(c2 => c2.Id).Contains(c1.Id)).ToList();
      

      另外,如果您有相同的实体/类型列表,您可以使用Except methpod(您需要定义自己的比较器)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-13
        • 1970-01-01
        • 2010-11-20
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 2019-03-19
        相关资源
        最近更新 更多