【问题标题】:Linq join without equals没有等号的 Linq 连接
【发布时间】:2012-05-14 09:04:50
【问题描述】:

我有一个矩形列表和一个点​​列表。我想构建一个 LINQ 查询,它将点列表与其对应的矩形相匹配。像这样的:

// Does not compile
var matches = from rect in rectangles
              join point in points on rect.Contains(point)
              select new { rect, point };

如何使用 LINQ 完成这样的事情?

编辑:

我的列表大小相同 - 我有一个点与一个矩形匹配,并且矩形不重叠。

但是,问题的重点并不是解决这一特定问题。一般来说,我感兴趣的是如何在任何条件下加入两个列表,而不是简单地“等于”。

【问题讨论】:

  • 学会爱上 LINQ 方法链,这样的问题就会瞬间消失。
  • 我其实更喜欢 LINQ 方法链——如果你能找到以这种方式解决这个问题的方法,我很乐意回答!
  • 矩形包含一个点对您意味着什么? System.Drawing.Rectangle 有一个位置点。您的意思是该点与矩形的位置点匹配还是在给定矩形区域内的某个位置?
  • @ConradFrix 这是我自己实现的矩形......这只是一个例子 - Contains() 内部发生的事情无关紧要;我只是在寻找一种在两个属性上没有简单“等于”的连接的方法。
  • @Phil,嗯,我说得太早了。完全忘记了Join 纯粹是基于密钥的。

标签: c# linq join


【解决方案1】:

你可以使用多个from子句来实现一个join

 var matches = from p in points
               from r in rectangles
               where r.Contains(p)
               select new { r, p };

多个 from 子句比连接语法 (see myth 5 of 10 LINQ myths) 更灵活。你只需要学习这个,所有的连接都会很容易。

【讨论】:

  • 请注意,对于不重叠的矩形,这实际上会执行相当多的额外工作,因为它会根据每个点检查每个矩形,并且不会在匹配的矩形出现后立即短路找到一个点。如果每个点都可以存在于 >1 个矩形中,这确实很好,但如果矩形不重叠,那就有点过头了。
  • +1 但正如@Reed Copsey 所提到的,这种查询对于大型数据集可能表现不佳。
  • 是的,叉积可能会变得非常昂贵,特别是如果您加入多个列表,您会获得指数(2 个二次方列表、3 个三次方、4 个双三次,...)的运行时间。
【解决方案2】:

您可以使用Enumerable.ToLookup 为每个矩形创建一个查找表:

var lookup = points.ToLookup(p => rectangles.First(r => r.Contains(point)));

使用它类似于分组查询:

foreach(var group in lookup)
{
    Console.WriteLine("Rectangle {0} contains:", group.Key);
    foreach(var point in group)
        Console.WriteLine("    {0}", point);
}

附带说明 - 此查询本质上是二次查询,并且在处理非常大的数据集时可能表现不佳。如果您需要对许多点和/或许多矩形执行此操作,您可能希望研究空间数据结构以便更快地查找。但是,在这种情况下,这可能不是问题。

【讨论】:

    【解决方案3】:

    您是否尝试过只使用 where 语句,而不是加入它们:

    var matches = from rectangle in rectangles
                  from point in points
                  where rectangle.Contains(point)
                  select new { rectangle, point };
    

    【讨论】:

      【解决方案4】:

      有两种方法可以得到你想要的。

      points.Select(p => new { Point = p, Rectangles = rectangles.Where(r => r.Contains(p) });
      

      这迎合了一个点可能在许多矩形中的情况。

      points.Select(p => new { Point = p, Rectangle = rectangles.First(r => r.Contains(p) });
      

      这迎合了一个点正好在一个矩形中的情况。

      第二种情况应该最适合您的方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多