2012-05-04 3 views
9

У меня есть список прямоугольников и список точек. Я хочу построить запрос LINQ, который будет соответствовать списку точек с соответствующими прямоугольниками. Что-то вроде этого:Linq join without equals

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

Как выполнить что-то подобное с помощью LINQ?

EDIT:

Мои списки одинакового размера - у меня есть один пункт, чтобы соответствовать с одного прямоугольника и прямоугольники не пересекаются.

Однако проблема заключается не столько в решении этой конкретной проблемы. В общем, мне интересно, как присоединиться к двум спискам при любых условиях, кроме просто «равно».

+0

Научитесь любить методы-цепочки LINQ и эти виды вопросов исчезают в мгновение ока. –

+0

Я на самом деле предпочитаю цепи методов LINQ - если вы можете найти способ решить эту проблему таким образом, я бы хотел ответить! – Phil

+0

Что это означает для вас, чтобы прямоугольник содержал точку? В System.Drawing.Rectangle есть точка местоположения. Вы имеете в виду, совпадает ли точка с точкой расположения прямоугольника или она находится где-то внутри области данного прямоугольника? –

ответ

14

Вы можете использовать несколько из статей для достижения присоединиться

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

Множественных из положения является более гибким, чем присоединиться к синтаксису (see myth 5 of 10 LINQ myths). Вам нужно изучить только этот, и все соединения будут легкими.

+0

Обратите внимание, что с неперекрывающимися прямоугольниками это фактически выполнит совсем немного дополнительной работы, так как будет проверять каждый прямоугольник на каждую точку, а не на короткое замыкание, как только будет найден подходящий прямоугольник для точки. Если каждая точка может существовать в прямоугольнике> 1, это действительно хорошо, но если прямоугольники не перекрываются, это будет излишним. –

+0

+1, но, как упоминалось @Reed Copsey, такой запрос может не работать хорошо для больших наборов данных. –

+0

Да, кросс-продукт может стать очень дорогим, особенно если вы присоединитесь к нескольким спискам, вы получаете экспоненциальный (2 списка квадратичных, 3 кубических, 4 бикубических, ...) времени работы. –

3

Вы можете использовать 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); 
} 

На стороне записки - этот запрос является квадратным по своей природе , и, вероятно, плохо работают с очень большими наборами данных. Если вам нужно сделать это для многих точек и/или многих прямоугольников, вы можете изучить структуры пространственных данных для более быстрого поиска. Однако это не может быть проблемой в этом случае.

1

Вы пробовали только с помощью где заявление, а не присоединиться к ним:

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

Есть два способа получить то, что вы хотите.

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

Это относится к случаю, когда точка находится ровно в одном прямоугольнике.

Второй случай должен работать лучше всего в вашем сценарии.