-2

I have a list of Objects which have a location [Rect].

I then select from this list, all Rects that fall inside a 'Column' (Left>x1 && Right<x2)

What I need to to now is find all Rects that are (roughly) in-line horizontally with each item in that list.

The only way I have found so far is to iterate over the list and check each rect individually for its Top value, but I feel this should be a lambda function.

Iterating code is as follows:

// Find all shapes on the page within these bounds
var BottomLeft = new Point(50, 45);
var TopRight = new Point(430, 770);

var allRects = allShapes.Where(sh => sh.BoundingBox.Bottom >= BottomLeft.Y
&& sh.BoundingBox.Left >= BottomLeft.X
&& sh.BoundingBox.Top <= TopRight.Y
&& sh.BoundingBox.Right <= TopRight.X).OrderByDescending(tb => tb.BoundingBox.Top);

// Select the rightmost column
var Col = allRects.Where(rt => rt.BoundingBox.Left > 365);

foreach (var rt in Col)
{
    var rct = allRects.Where(tb => Math.Abs(tb.BoundingBox.Top - rt.BoundingBox.Top) < 2);
    /// etc...
    
}

How would I convert the foreach loop into a lambda query?

4
  • FYI: you have multiple enumerations of sequence with OrderByDescending - that's an expensive operation Commented Jun 20 at 11:12
  • So would it be better to order the list at the very end of the process? Just trying to save as much processing time as I can. Commented Jun 20 at 11:36
  • 3
    Please finish the etc... part, or tell us what the result should be, why did you think this should be a lambda function? Commented Jun 20 at 12:18
  • 2
    I agree with @shingo - the etc... is the most important part to understand what your expected result is. Commented Jun 20 at 13:00

1 Answer 1

1

You can convert your foreach loop into a LINQ expression using Select to project each rt from Col along with its horizontally-aligned matches from allRects. Here's how it could look:

var alignedGroups = Col
    .Select(rt => new
    {
        Reference = rt,
        Aligned = allRects.Where(tb => Math.Abs(tb.BoundingBox.Top - rt.BoundingBox.Top) < 2)
    });

This gives you an IEnumerable of anonymous objects, each containing a Reference rect (rt) and a list of Aligned rects that are roughly on the same horizontal line (within ±2 units in Y).

If you want just a flat list of all aligned rects (without grouping them by reference), you could use SelectMany:

var alignedRects = Col
    .SelectMany(rt => allRects.Where(tb => Math.Abs(tb.BoundingBox.Top - rt.BoundingBox.Top) < 2));

This mirrors the logic from your loop, just in a more functional (lambda) style.

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect.... That was exactly what I was looking for. Thank you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.