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
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
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
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
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
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;
reverse
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
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
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
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