From Expressions (LINQ)

from expressions provide an elegant SQL-like way to perform query operations on a Sequence, Array or other collection.

This includes ways to filter, sort, group and join sets of data.

A from expression (also referred to as a LINQ expression, short for "Language INtegrated Query") always starts with the keyword from, and its result is a new Sequence of the same or a derived (and possibly anonymous) type.

var lNames := from p in People
                where p.Age ≥ 18
                select p.Name;

The beginning of the expression is formed by the two keywords from and in. Much like a for i in, the in keyword is followed by the sequence to be iterated, and preceded by a new variable that is introduced for the iteration. This variable is available throughout the rest of the expression to refer to an individual item in the sequence.

Following the preamble can be one or more query sub-expressions, such as the where and select expressions in the example above. When the LINQ expression is later executed, each sub expression is applies to the result of its predecessor.

In the above example from p in People is the origfinal sequence of all items in the People collection. where p.Age > 18 executes over each of these items, returning a new sequence that contains only those matching the condition (p.Age ≥ 18). select p.Name then runs over that sequence, i.e. only the persons age 18 or above, and it will return a new sequence that has each adult's name, instead of the full data.

As a result, lNames will be a sequence of String, containing the name value from all people whose age value was 18 or above.

LINQ Query Operators

The following query operators, or sub-expressions, are supported:


where can be used to filter a sequence. The expression should return a boolean where true indicates this value will be included in the result.

var lTallPeople := from p in People where p.Height > 200;


from can also be used as a sub-expression, to introduce a sub-sequence into scope. Both the original identifier and the new variable are available in scope, afterwards:

var lChapters :=
  from book in Books
  from chapter in book.Chapters
  where book.Author = "Stephen King" and chapter.length > 50
  select Book.Title+", Chapter "+Chapter.Title;
  // all chapters by Stephe King that are longer than 50 pages


with can be used to evaluate a sub-expression, store it, and give it a name, so it can be reused in additional queries.

var s := "A sentence";
var vowels := from letter in s
  with lower := Char.ToLower(letter)
  where lower in ['e', 'u', 'i', 'o', 'a']


join expressions can join two seperate collections together. An optional into clause can change the name of the resulting identifier.

var lBooksWithAuthor := from b in Books
  join a in Authors on b.Author equals author.ID
  select new class (Book := b, Author = a);

order by (descending)

order by is used to sort a sequence in a specific order. It expects an expression that is comparable. To sort by multiple criteria, more than one exprerssion can be provided, separated with a comma. An optional ascecnding (default) or descecnding modifier can be appended after each expression to reverse the order.

var lSorted := from p in People 
  order by p.Name ascending, p.Age descending 
  select p.Name+", age "+p.Age;


select can be used to convert each item of the sequence to a derived value, which can be of the same or a different type. When select is not the final query operator in the expression, the into keyword has to be used to provide a new identifier for the rest of the expression.

var lShortPasswords := from u in Users 
  where not u.Disabled
  select u.Password into p 
  where p.Length < 8;

group by

group by is used to partition a sequence into sub-groups by an expression.

The result returns a grouped sequence with one entry for each group, which contains both the shared value, as well as all items of the subgroup as nested sequence.

When this is not the final query operator in the expression, the into keyword has to be used to provide a new identifier for the rest of the expression. The identifier after group is implied to be the current LINQ query identifier, if it's omitted.

var lPeopleByAge = from p in People
  group s by s.Age;


As the name implies, reverse reverses the order in which things are returned.

var x := [1,2,3,4,5];
var y := from a in x reverse;
// 5,4,3,2,1


distinct filters out duplicates items in a sequence, so that each unique value is only contained once in the result.

var x := [1,2,3,2,4,4,5];
var y := from a in x distinct;
// 1,2,3,4,5


take takes a limited number of elements from the collection and stops returning after that.

var x := [1,2,3,4,5,6,7];
var y := from a in x take 5;
// 1,2,3,4,5

take while returns items as long as the provided expression returns true.

var x := [1,2,3,4,5,4,3,2,1,0];
var y := from a in x take while a < 4;
// 1,2,3


skip skips a number of elements before returning from the collection. If the end of the collection is reached before the appropriate number of items where skipped, the resulting sequence will be empty.

var x := [1,2,3,4,5,6,7];
var y := from a in x skip 3;
// 4,5,6,7

skip while skips items as long as the expression returns true.

var x := [1,2,3,4,5,4,3,2,1];
var y := from a in x skip while a < 4 select a;
// 4,5,4,3,2,1

See Also