Richard Pawson
Richard Pawson

Reputation: 1526

How to convert Linq-to-objects query with two from clauses to method syntax

How do I convert this LINQ query syntax (this is LINQ to objects) to method syntax:

var occupiedSquares = from s in squares
               from p in pieces
               where Occupies(p, s)
               select s;

(Occupies is a function returning bool. But note that a square does not directly hold a list of occupying pieces, nor does a piece directly hold a list of squares it occupies.).

I thought the answer might useJoin, but I can't seem to make it fit the join syntax, because there isn't a common key. (And does the Join method even work on LINQ to objects?).

Upvotes: 0

Views: 129

Answers (1)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112447

Two consecutive from-clauses are translated with a SelectMany extension method:

var occupiedSquares = squares
    .SelectMany(s => pieces.Select(p => (s, p))) // Creates a ValueTuple
    .Where(x => Occupies(x.p, x.s))
    .Select(x => x.s);

If you are working with an older Framework version, you can also use an Anonymous Type instead of a ValueTuple.

var occupiedSquares = squares
    .SelectMany(s => pieces.Select(p => new { s, p }))
    .Where(x => Occupies(x.p, x.s))
    .Select(x => x.s);

Alternatively, you can also apply the Where-clause to the nested Select. No aggregate (ValueTuple or anonymous type) is required in this case:

var occupiedSquares = squares
    .SelectMany(
        s => pieces
            .Where(p => Occupies(p, s))
            .Select(p => s)
    );

The Enumerable.SelectMany Method is typically used to flatten a nested collection. E.g., you have a list of users and the user objects have a list of posts and you need a list of all the posts.

See also my question Nested “from” LINQ query expressed with extension methods and Eric Lippert's answer. (Eric was part of Microsoft's C# compiler team.)

Upvotes: 1

Related Questions