Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 56

Restriction Operators

Where - Simple 1

This sample uses where to find all elements of an array less than 5.

public void Linq1()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var lowNums =
from n in numbers
where n < 5
select n;

Console.WriteLine("Numbers < 5:");


foreach (var x in lowNums)
{
Console.WriteLine(x);
}
}

Result

Numbers < 5:
4
1
3
2
0

Where - Simple 2

This sample uses where to find all products that are out of stock.

public void Linq2()


{
List<Product> products = GetProductList();

var soldOutProducts =
from p in products
where p.UnitsInStock == 0
select p;

Console.WriteLine("Sold out products:");


foreach (var product in soldOutProducts)
{
Console.WriteLine("{0} is sold out!", product.ProductName);
}
}
Result

Sold out products:


Chef Anton's Gumbo Mix is sold out!
Alice Mutton is sold out!
Thüringer Rostbratwurst is sold out!
Gorgonzola Telino is sold out!
Perth Pasties is sold out!

Where - Simple 3

This sample uses where to find all products that are in stock and cost more than 3.00 per unit.

public void Linq3()


{
List<Product> products = GetProductList();

var expensiveInStockProducts =
from p in products
where p.UnitsInStock > 0 && p.UnitPrice > 3.00M
select p;

Console.WriteLine("In-stock products that cost more than 3.00:");


foreach (var product in expensiveInStockProducts)
{
Console.WriteLine("{0} is in stock and costs more than 3.00.",
product.ProductName);
}
}

Result

In-stock products that cost more than 3.00:


Chai is in stock and costs more than 3.00.
Chang is in stock and costs more than 3.00.
Aniseed Syrup is in stock and costs more than 3.00.

Where - Drilldown

This sample uses where to find all customers in Washington and then uses the resulting sequence
to drill down into their orders.

public void Linq4()


{
List<Customer> customers = GetCustomerList();
var waCustomers =
from c in customers
where c.Region == "WA"
select c;

Console.WriteLine("Customers from Washington and their orders:");


foreach (var customer in waCustomers)
{
Console.WriteLine("Customer {0}: {1}", customer.CustomerID,
customer.CompanyName);
foreach (var order in customer.Orders)
{
Console.WriteLine(" Order {0}: {1}", order.OrderID,
order.OrderDate);
}
}
}

Result

Customers from Washington and their orders:


Customer LAZYK: Lazy K Kountry Store
Order 10482: 3/21/1997 12:00:00 AM

Where - Indexed

This sample demonstrates an indexed Where clause that returns digits whose name is shorter
than their value.

public void Linq5()


{
string[] digits = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };

var shortDigits = digits.Where((digit, index) => digit.Length < index);

Console.WriteLine("Short digits:");
foreach (var d in shortDigits)
{
Console.WriteLine("The word {0} is shorter than its value.", d);
}
}

Result

Short digits:
The word five is shorter than its value.
The word six is shorter than its value.
The word seven is shorter than its value.
The word eight is shorter than its value.
The word nine is shorter than its value.

Projection Operators

Select - Simple 1
This sample uses select to produce a sequence of ints one higher than those in an existing array
of ints.

public void Linq6()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var numsPlusOne =
from n in numbers
select n + 1;

Console.WriteLine("Numbers + 1:");
foreach (var i in numsPlusOne)
{
Console.WriteLine(i);
}
}

Result

Numbers + 1:
6
5
2
4
10
9
7
8
3
1

Select - Simple 2

This sample uses select to return a sequence of just the names of a list of products.

public void Linq7()


{
List<Product> products = GetProductList();
var productNames =
from p in products
select p.ProductName;

Console.WriteLine("Product Names:");
foreach (var productName in productNames)
{
Console.WriteLine(productName);
}
}

Result
Product Names:
Chai
Chang
Aniseed Syrup

Select - Transformation

This sample uses select to produce a sequence of strings representing the text version of a
sequence of ints.

public void Linq8()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
string[] strings = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };

var textNums =
from n in numbers
select strings[n];

Console.WriteLine("Number strings:");
foreach (var s in textNums)
{
Console.WriteLine(s);
}
}

Result

Number strings:
five
four
one
three
nine
eight
six
seven
two
zero

Select - Anonymous Types 1

This sample uses select to produce a sequence of the uppercase and lowercase versions of each
word in the original array.

public void Linq9()


{
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };

var upperLowerWords =
from w in words
select new { Upper = w.ToUpper(), Lower = w.ToLower() };

foreach (var ul in upperLowerWords)


{
Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper,
ul.Lower);
}
}

Result

Uppercase: APPLE, Lowercase: apple


Uppercase: BLUEBERRY, Lowercase: blueberry
Uppercase: CHERRY, Lowercase: cherry

Select - Anonymous Types 2

This sample uses select to produce a sequence containing text representations of digits and
whether their length is even or odd.

public void Linq10()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
string[] strings = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };

var digitOddEvens =
from n in numbers
select new { Digit = strings[n], Even = (n % 2 == 0) };

foreach (var d in digitOddEvens)


{
Console.WriteLine("The digit {0} is {1}.", d.Digit, d.Even ? "even" :
"odd");
}
}

Result

The digit five is odd.


The digit four is even.
The digit one is odd.
The digit three is odd.
The digit nine is odd.
The digit eight is even.
The digit six is even.
The digit seven is odd.
The digit two is even.
The digit zero is even.

Select - Anonymous Types 3

This sample uses select to produce a sequence containing some properties of Products, including
UnitPrice which is renamed to Price in the resulting type.

public void Linq11()


{
List<Product> products = GetProductList();

var productInfos =
from p in products
select new { p.ProductName, p.Category, Price = p.UnitPrice };

Console.WriteLine("Product Info:");
foreach (var productInfo in productInfos)
{
Console.WriteLine("{0} is in the category {1} and costs {2} per
unit.", productInfo.ProductName, productInfo.Category, productInfo.Price);
}
}

Result

Product Info:
Chai is in the category Beverages and costs 18.0000 per unit.
Chang is in the category Beverages and costs 19.0000 per unit.

Select - Indexed

This sample uses an indexed Select clause to determine if the value of ints in an array match their
position in the array.

public void Linq12()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var numsInPlace = numbers.Select((num, index) => new { Num = num, InPlace


= (num == index) });

Console.WriteLine("Number: In-place?");
foreach (var n in numsInPlace)
{
Console.WriteLine("{0}: {1}", n.Num, n.InPlace);
}
}

Result
Number: In-place?
5: False
4: False
1: False
3: True
9: False
8: False
6: True
7: True
2: False
0: False

Select - Filtered

This sample combines select and where to make a simple query that returns the text form of each
digit less than 5.

public void Linq13()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
string[] digits = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };

var lowNums =
from n in numbers
where n < 5
select digits[n];

Console.WriteLine("Numbers < 5:");


foreach (var num in lowNums)
{
Console.WriteLine(num);
}
}

Result

Numbers < 5:
four
one
three
two
zero

SelectMany - Compound from 1

This sample uses a compound from clause to make a query that returns all pairs of numbers from
both arrays such that the number from numbersA is less than the number from numbersB.
public void Linq14()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };

var pairs =
from a in numbersA
from b in numbersB
where a < b
select new { a, b };

Console.WriteLine("Pairs where a < b:");


foreach (var pair in pairs)
{
Console.WriteLine("{0} is less than {1}", pair.a, pair.b);
}
}

Result

Pairs where a < b:


0 is less than 1

SelectMany - Compound from 2

This sample uses a compound from clause to select all orders where the order total is less than
500.00.

public void Linq15()


{
List<Customer> customers = GetCustomerList();

var orders =
from c in customers
from o in c.Orders
where o.Total < 500.00M
select new { c.CustomerID, o.OrderID, o.Total };

ObjectDumper.Write(orders);
}

Result

CustomerID=ALFKI OrderID=10702 Total=330.00


CustomerID=ALFKI OrderID=10952 Total=471.20

SelectMany - Compound from 3


This sample uses a compound from clause to select all orders where the order was made in 1998
or later.

public void Linq16()


{
List<Customer> customers = GetCustomerList();

var orders =
from c in customers
from o in c.Orders
where o.OrderDate >= new DateTime(1998, 1, 1)
select new { c.CustomerID, o.OrderID, o.OrderDate };

ObjectDumper.Write(orders);
}

Result

CustomerID=ALFKI OrderID=10835 OrderDate=1/15/1998


CustomerID=ALFKI OrderID=10952 OrderDate=3/16/1998
CustomerID=ALFKI OrderID=11011 OrderDate=4/9/1998

SelectMany - Indexed

This sample uses an indexed SelectMany clause to select all orders, while referring to customers
by the order in which they are returned from the query.

public void Linq19()


{
List<Customer> customers = GetCustomerList();

var customerOrders =
customers.SelectMany(
(cust, custIndex) =>
cust.Orders.Select(o => "Customer #" + (custIndex + 1) +
" has an order with OrderID " +
o.OrderID));

ObjectDumper.Write(customerOrders);
}

Result

Customer #1 has an order with OrderID 10643


Customer #1 has an order with OrderID 10692
Partitioning Operators

Take - Simple

This sample uses Take to get only the first 3 elements of the array.

public void Linq20()

{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var first3Numbers = numbers.Take(3);
Console.WriteLine("First 3 numbers:");
foreach (var n in first3Numbers)
{
Console.WriteLine(n);
}
}

Result

First 3 numbers:
5
4
1

Take - Nested

This sample uses Take to get the first 3 orders from customers in Washington.

public void Linq21()

{
List<Customer> customers = GetCustomerList();

var first3WAOrders = (
from c in customers
from o in c.Orders
where c.Region == "WA"
select new { c.CustomerID, o.OrderID, o.OrderDate })
.Take(3);
Console.WriteLine("First 3 orders in WA:");
foreach (var order in first3WAOrders)
{
ObjectDumper.Write(order);
}
}

Result

First 3 orders in WA:


CustomerID=LAZYK OrderID=10482 OrderDate=3/21/1997
CustomerID=LAZYK OrderID=10545 OrderDate=5/22/1997
CustomerID=TRAIH OrderID=10574 OrderDate=6/19/1997

Skip - Simple

This sample uses Skip to get all but the first 4 elements of the array.

public void Linq22()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var allButFirst4Numbers = numbers.Skip(4);
Console.WriteLine("All but first 4 numbers:");
foreach (var n in allButFirst4Numbers)
{
Console.WriteLine(n);
}
}

Result

All but first 4 numbers:


9
8
6
7
2
0

Skip - Nested

This sample uses Take to get all but the first 2 orders from customers in Washington.

public void Linq23()


{
List<Customer> customers = GetCustomerList();

var waOrders =
from c in customers
from o in c.Orders
where c.Region == "WA"
select new { c.CustomerID, o.OrderID, o.OrderDate };

var allButFirst2Orders = waOrders.Skip(2);


Console.WriteLine("All but first 2 orders in WA:");
foreach (var order in allButFirst2Orders)
{
ObjectDumper.Write(order);
}
}

Result
All but first 2 orders in WA:
CustomerID=TRAIH OrderID=10574 OrderDate=6/19/1997
CustomerID=TRAIH OrderID=10577 OrderDate=6/23/1997

TakeWhile - Simple

This sample uses TakeWhile to return elements starting from the beginning of the array until a
number is hit that is not less than 6.

public void Linq24()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
Console.WriteLine("First numbers less than 6:");
foreach (var n in firstNumbersLessThan6)
{
Console.WriteLine(n);
}
}

Result

First numbers less than 6:


5
4
1
3

TakeWhile - Indexed

This sample uses TakeWhile to return elements starting from the beginning of the array until a
number is hit that is less than its position in the array.

public void Linq25()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
Console.WriteLine("First numbers not less than their position:");
foreach (var n in firstSmallNumbers)
{
Console.WriteLine(n);
}
}

Result

First numbers not less than their position:


5
4
SkipWhile - Simple

This sample uses SkipWhile to get the elements of the array starting from the first element
divisible by 3.

public void Linq26()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var allButFirst3Numbers = numbers.SkipWhile(n => n % 3 != 0);

Console.WriteLine("All elements starting from first element divisible by


3:");

foreach (var n in allButFirst3Numbers)


{
Console.WriteLine(n);
}
}

Result

All elements starting from first element divisible by 3:


3
9
8
6
7
2
0

SkipWhile - Indexed

This sample uses SkipWhile to get the elements of the array starting from the first element less
than its position.

public void Linq27()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var laterNumbers = numbers.SkipWhile((n, index) => n >= index);
Console.WriteLine("All elements starting from first element less than its
position:");

foreach (var n in laterNumbers)


{
Console.WriteLine(n);
}
}

Result
All elements starting from first element less than its position:
1
3
9
8
6
7
2
0

Ordering Operators

OrderBy - Simple 1

This sample uses orderby to sort a list of words alphabetically.

public void Linq28()


{
string[] words = { "cherry", "apple", "blueberry" };

var sortedWords =
from w in words
orderby w
select w;

Console.WriteLine("The sorted list of words:");


foreach (var w in sortedWords)
{
Console.WriteLine(w);
}
}

Result

The sorted list of words:


apple
blueberry
cherry

OrderBy - Simple 2

This sample uses orderby to sort a list of words by length.

public void Linq29()


{
string[] words = { "cherry", "apple", "blueberry" };

var sortedWords =
from w in words
orderby w.Length
select w;

Console.WriteLine("The sorted list of words (by length):");


foreach (var w in sortedWords)
{
Console.WriteLine(w);
}
}

Result

The sorted list of words (by length):


apple
cherry
blueberry

OrderBy - Simple 3

This sample uses orderby to sort a list of products by name.

public void Linq30()


{
List<Product> products = GetProductList();

var sortedProducts =
from p in products
orderby p.ProductName
select p;

ObjectDumper.Write(sortedProducts);
}

Result

ProductID=17 ProductName=Alice Mutton Category=Meat/Poultry UnitPrice=39.0000


UnitsInStock=0
ProductID=3 ProductName=Aniseed Syrup Category=Condiments UnitPrice=10.0000
UnitsInStock=13

OrderBy - Comparer

This sample uses an OrderBy clause with a custom comparer to do a case-insensitive sort of the
words in an array.

public void Linq31()


{
string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr",
"cHeRry" };
var sortedWords = words.OrderBy(a => a, new CaseInsensitiveComparer());

ObjectDumper.Write(sortedWords);
}

public class CaseInsensitiveComparer : IComparer<string>


{
public int Compare(string x, string y)
{
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}
}

Result

AbAcUs
aPPLE
BlUeBeRrY
bRaNcH
cHeRry
ClOvEr

OrderByDescending - Simple 1

This sample uses orderby and descending to sort a list of doubles from highest to lowest.

public void Linq32()


{
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };

var sortedDoubles =
from d in doubles
orderby d descending
select d;

Console.WriteLine("The doubles from highest to lowest:");


foreach (var d in sortedDoubles)
{
Console.WriteLine(d);
}
}

Result

The doubles from highest to lowest:


4.1
2.9
2.3
1.9
1.7
OrderByDescending - Simple 2

This sample uses orderby to sort a list of products by units in stock from highest to lowest.

public void Linq33()


{
List<Product> products = GetProductList();

var sortedProducts =
from p in products
orderby p.UnitsInStock descending
select p;

ObjectDumper.Write(sortedProducts);
}

Result

ProductID=75 ProductName=Rhönbräu Klosterbier Category=Beverages UnitPrice=7.7500


UnitsInStock=125
ProductID=40 ProductName=Boston Crab Meat Category=Seafood UnitPrice=18.4000
UnitsInStock=123
ProductID=6 ProductName=Grandma's Boysenberry Spread Category=Condiments
UnitPrice=25.0000 UnitsInStock=120
ProductID=55 ProductName=Pâté chinois Category=Meat/Poultry UnitPrice=24.0000
UnitsInStock=115
ProductID=61 ProductName=Sirop d'érable Category=Condiments UnitPrice=28.5000
UnitsInStock=113
ProductID=33 ProductName=Geitost Category=Dairy Products UnitPrice=2.5000
UnitsInStock=112

OrderByDescending - Comparer

This sample uses an OrderBy clause with a custom comparer to do a case-insensitive descending
sort of the words in an array.

public void Linq34()


{
string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr",
"cHeRry" };

var sortedWords = words.OrderByDescending(a => a, new


CaseInsensitiveComparer());

ObjectDumper.Write(sortedWords);
}

public class CaseInsensitiveComparer : IComparer<string>


{
public int Compare(string x, string y)
{
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}
}

Result

ClOvEr
cHeRry
bRaNcH
BlUeBeRrY
aPPLE
AbAcUs

ThenBy - Simple

This sample uses a compound orderby to sort a list of digits, first by length of their name, and
then alphabetically by the name itself.

public void Linq35()


{
string[] digits = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };

var sortedDigits =
from d in digits
orderby d.Length, d
select d;

Console.WriteLine("Sorted digits:");
foreach (var d in sortedDigits)
{
Console.WriteLine(d);
}
}

Result

Sorted digits:
one
six
two
five
four
nine
zero
eight
seven
three
ThenBy - Comparer

This sample uses an OrderBy and a ThenBy clause with a custom comparer to sort first by word
length and then by a case-insensitive sort of the words in an array.

public void Linq36()


{
string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr",
"cHeRry" };

var sortedWords =
words.OrderBy(a => a.Length)
.ThenBy(a => a, new CaseInsensitiveComparer());

ObjectDumper.Write(sortedWords);
}

public class CaseInsensitiveComparer : IComparer<string>


{
public int Compare(string x, string y)
{
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}
}

Result

aPPLE
AbAcUs
bRaNcH
cHeRry
ClOvEr
BlUeBeRrY

ThenByDescending - Simple

This sample uses a compound orderby to sort a list of products, first by category, and then by
unit price, from highest to lowest.

public void Linq37()


{
List<Product> products = GetProductList();

var sortedProducts =
from p in products
orderby p.Category, p.UnitPrice descending
select p;

ObjectDumper.Write(sortedProducts);
}
Result

ProductID=38 ProductName=Côte de Blaye Category=Beverages UnitPrice=263.5000


UnitsInStock=17
ProductID=43 ProductName=Ipoh Coffee Category=Beverages UnitPrice=46.0000
UnitsInStock=17
ProductID=2 ProductName=Chang Category=Beverages UnitPrice=19.0000 UnitsInStock=17
ProductID=1 ProductName=Chai Category=Beverages UnitPrice=18.0000 UnitsInStock=39
ProductID=35 ProductName=Steeleye Stout Category=Beverages UnitPrice=18.0000
UnitsInStock=20

ThenByDescending - Comparer

This sample uses an OrderBy and a ThenBy clause with a custom comparer to sort first by word
length and then by a case-insensitive descending sort of the words in an array.

public void Linq38()


{
string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr",
"cHeRry" };

var sortedWords =
words.OrderBy(a => a.Length)
.ThenByDescending(a => a, new CaseInsensitiveComparer());

ObjectDumper.Write(sortedWords);
}

public class CaseInsensitiveComparer : IComparer<string>


{
public int Compare(string x, string y)
{
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}
}

Result

aPPLE
ClOvEr
cHeRry
bRaNcH
AbAcUs
BlUeBeRrY

Reverse
This sample uses Reverse to create a list of all digits in the array whose second letter is 'i' that is
reversed from the order in the original array.

public void Linq39()


{
string[] digits = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };

var reversedIDigits = (
from d in digits
where d[1] == 'i'
select d)
.Reverse();

Console.WriteLine("A backwards list of the digits with a second character


of 'i':");
foreach (var d in reversedIDigits)
{
Console.WriteLine(d);
}
}

Result

A backwards list of the digits with a second character of 'i':


nine
eight
six
five

Grouping Operators

GroupBy - Simple 1

This sample uses group by to partition a list of numbers by their remainder when divided by 5.

public void Linq40()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var numberGroups =
from n in numbers
group n by n % 5 into g
select new { Remainder = g.Key, Numbers = g };

foreach (var g in numberGroups)


{
Console.WriteLine("Numbers with a remainder of {0} when divided by
5:", g.Remainder);
foreach (var n in g.Numbers)
{
Console.WriteLine(n);
}
}
}

Result

Numbers with a remainder of 0 when divided by 5:


5
0
Numbers with a remainder of 4 when divided by 5:
4
9
Numbers with a remainder of 1 when divided by 5:
1
6
Numbers with a remainder of 3 when divided by 5:
3
8
Numbers with a remainder of 2 when divided by 5:
7
2

GroupBy - Simple 2

This sample uses group by to partition a list of words by their first letter.

public void Linq41()


{
string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple",
"cheese" };

var wordGroups =
from w in words
group w by w[0] into g
select new { FirstLetter = g.Key, Words = g };

foreach (var g in wordGroups)


{
Console.WriteLine("Words that start with the letter '{0}':",
g.FirstLetter);
foreach (var w in g.Words)
{
Console.WriteLine(w);
}
}
}

Result
Words that start with the letter 'b':
blueberry
banana
Words that start with the letter 'c':
chimpanzee
cheese
Words that start with the letter 'a':
abacus
apple

GroupBy - Simple 3

This sample uses group by to partition a list of products by category.

public void Linq42()


{
List<Product> products = GetProductList();

var orderGroups =
from p in products
group p by p.Category into g
select new { Category = g.Key, Products = g };

ObjectDumper.Write(orderGroups, 1);
}

Result

Category=Beverages Products=...
Products: ProductID=1 ProductName=Chai Category=Beverages UnitPrice=18.0000
UnitsInStock=39

GroupBy - Nested

This sample uses group by to partition a list of each customer's orders, first by year, and then by
month.

public void Linq43()


{
List<Customer> customers = GetCustomerList();

var customerOrderGroups =
from c in customers
select
new
{
c.CompanyName,
YearGroups =
from o in c.Orders
group o by o.OrderDate.Year into yg
select
new
{
Year = yg.Key,
MonthGroups =
from o in yg
group o by o.OrderDate.Month into mg
select new { Month = mg.Key, Orders = mg }
}
};

ObjectDumper.Write(customerOrderGroups, 3);
}

Result

CompanyName=Alfreds Futterkiste YearGroups=...


YearGroups: Year=1997 MonthGroups=...
MonthGroups: Month=8 Orders=...
Orders: OrderID=10643 OrderDate=8/25/1997 Total=814.50

GroupBy - Comparer

This sample uses GroupBy to partition trimmed elements of an array using a custom comparer
that matches words that are anagrams of each other.

public void Linq44()


{
string[] anagrams = { "from ", " salt", " earn ", " last ", " near ",
" form " };

var orderGroups = anagrams.GroupBy(w => w.Trim(), new


AnagramEqualityComparer());

ObjectDumper.Write(orderGroups, 1);
}

public class AnagramEqualityComparer : IEqualityComparer<string>


{
public bool Equals(string x, string y)
{
return getCanonicalString(x) == getCanonicalString(y);
}

public int GetHashCode(string obj)


{
return getCanonicalString(obj).GetHashCode();
}

private string getCanonicalString(string word)


{
char[] wordChars = word.ToCharArray();
Array.Sort<char>(wordChars);
return new string(wordChars);
}
}

Result

...
from
form
...
salt
last
...
earn
near

GroupBy - Comparer, Mapped

This sample uses GroupBy to partition trimmed elements of an array using a custom comparer
that matches words that are anagrams of each other, and then converts the results to uppercase.

public void Linq45()


{
string[] anagrams = { "from ", " salt", " earn ", " last ", " near ",
" form " };

var orderGroups = anagrams.GroupBy(


w => w.Trim(),
a => a.ToUpper(),
new AnagramEqualityComparer()
);

ObjectDumper.Write(orderGroups, 1);
}

public class AnagramEqualityComparer : IEqualityComparer<string>


{
public bool Equals(string x, string y)
{
return getCanonicalString(x) == getCanonicalString(y);
}

public int GetHashCode(string obj)


{
return getCanonicalString(obj).GetHashCode();
}

private string getCanonicalString(string word)


{
char[] wordChars = word.ToCharArray();
Array.Sort<char>(wordChars);
return new string(wordChars);
}
}

Result

...
FROM
FORM
...
SALT
LAST
...
EARN
NEAR

Set Operators

Distinct - 1

This sample uses Distinct to remove duplicate elements in a sequence of factors of 300.

public void Linq46()


{
int[] factorsOf300 = { 2, 2, 3, 5, 5 };

var uniqueFactors = factorsOf300.Distinct();

Console.WriteLine("Prime factors of 300:");


foreach (var f in uniqueFactors)
{
Console.WriteLine(f);
}
}

Result

Prime factors of 300:


2
3
5

Distinct - 2

This sample uses Distinct to find the unique Category names.

public void Linq47()


{
List<Product> products = GetProductList();

var categoryNames = (
from p in products
select p.Category)
.Distinct();

Console.WriteLine("Category names:");
foreach (var n in categoryNames)
{
Console.WriteLine(n);
}
}

Result

Category names:
Beverages
Condiments
Produce
Meat/Poultry
Seafood
Dairy Products
Confections
Grains/Cereals

Union - 1

This sample uses Union to create one sequence that contains the unique values from both arrays.

public void Linq48()


{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };

var uniqueNumbers = numbersA.Union(numbersB);

Console.WriteLine("Unique numbers from both arrays:");


foreach (var n in uniqueNumbers)
{
Console.WriteLine(n);
}
}

Result

Unique numbers from both arrays:


0
2
4
5
6
8
9
1
3
7

Union - 2

This sample uses Union to create one sequence that contains the unique first letter from both
product and customer names.

public void Linq49()


{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();

var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];

var uniqueFirstChars = productFirstChars.Union(customerFirstChars);

Console.WriteLine("Unique first letters from Product names and Customer


names:");
foreach (var ch in uniqueFirstChars)
{
Console.WriteLine(ch);
}
}

Result

Unique first letters from Product names and Customer names:


C
A
G
U
N

Intersect - 1

This sample uses Intersect to create one sequence that contains the common values shared by
both arrays.
public void Linq50()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };

var commonNumbers = numbersA.Intersect(numbersB);

Console.WriteLine("Common numbers shared by both arrays:");


foreach (var n in commonNumbers)
{
Console.WriteLine(n);
}
}

Result

Common numbers shared by both arrays:


5
8

Intersect - 2

This sample uses Intersect to create one sequence that contains the common first letter from both
product and customer names.

public void Linq51()


{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();

var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];

var commonFirstChars = productFirstChars.Intersect(customerFirstChars);

Console.WriteLine("Common first letters from Product names and Customer


names:");
foreach (var ch in commonFirstChars)
{
Console.WriteLine(ch);
}
}

Result

Common first letters from Product names and Customer names:


C
A

Except - 1

This sample uses Except to create a sequence that contains the values from numbersAthat are not
also in numbersB.

public void Linq52()


{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };

IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);

Console.WriteLine("Numbers in first array but not second array:");


foreach (var n in aOnlyNumbers)
{
Console.WriteLine(n);
}
}

Result

Numbers in first array but not second array:


0
2
4
6
9

Except - 2

This sample uses Except to create one sequence that contains the first letters of product names
that are not also first letters of customer names.

public void Linq53()


{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();

var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];

var productOnlyFirstChars = productFirstChars.Except(customerFirstChars);


Console.WriteLine("First letters from Product names, but not from Customer
names:");
foreach (var ch in productOnlyFirstChars)
{
Console.WriteLine(ch);
}
}

Result

First letters from Product names, but not from Customer names:
U
J
Z

Conversion Operators

ToArray

This sample uses ToArray to immediately evaluate a sequence into an array.

public void Linq54()


{
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };

var sortedDoubles =
from d in doubles
orderby d descending
select d;
var doublesArray = sortedDoubles.ToArray();

Console.WriteLine("Every other double from highest to lowest:");


for (int d = 0; d < doublesArray.Length; d += 2)
{
Console.WriteLine(doublesArray[d]);
}
}

Result

Every other double from highest to lowest:


4.1
2.3
1.7

ToList

This sample uses ToList to immediately evaluate a sequence into a List<T>.


public void Linq55()
{
string[] words = { "cherry", "apple", "blueberry" };

var sortedWords =
from w in words
orderby w
select w;
var wordList = sortedWords.ToList();

Console.WriteLine("The sorted word list:");


foreach (var w in wordList)
{
Console.WriteLine(w);
}
}

Result

The sorted word list:


apple
blueberry
cherry

ToDictionary

This sample uses ToDictionary to immediately evaluate a sequence and a related key expression
into a dictionary.

public void Linq56()


{
var scoreRecords = new[] { new {Name = "Alice", Score = 50},
new {Name = "Bob" , Score = 40},
new {Name = "Cathy", Score = 45}
};

var scoreRecordsDict = scoreRecords.ToDictionary(sr => sr.Name);

Console.WriteLine("Bob's score: {0}", scoreRecordsDict["Bob"]);


}

Result

Bob's score: { Name = Bob, Score = 40 }

OfType

This sample uses OfType to return only the elements of the array that are of type double.

public void Linq57()


{
object[] numbers = { null, 1.0, "two", 3, "four", 5, "six", 7.0 };

var doubles = numbers.OfType<double>();

Console.WriteLine("Numbers stored as doubles:");


foreach (var d in doubles)
{
Console.WriteLine(d);
}
}

Result

Numbers stored as doubles:


1
7

Element Operators

First - Simple

This sample uses First to return the first matching element as a Product, instead of as a sequence
containing a Product.

public void Linq58()

List<Product> products = GetProductList();

Product product12 = (

from p in products

where p.ProductID == 12

select p)

.First();

ObjectDumper.Write(product12);

Result
ProductID=12 ProductName=Queso Manchego La Pastora Category=Dairy Products
UnitPrice=38.0000 UnitsInStock=86

First - Condition

This sample uses First to find the first element in the array that starts with 'o'.

public void Linq59()


{
string[] strings = { "zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine" };
string startsWithO = strings.First(s => s[0] == 'o');
Console.WriteLine("A string starting with 'o': {0}", startsWithO);
}

Result

A string starting with 'o': one

FirstOrDefault - Simple

This sample uses FirstOrDefault to try to return the first element of the sequence, unless there are
no elements, in which case the default value for that type is returned.

public void Linq61()


{
int[] numbers = { };
int firstNumOrDefault = numbers.FirstOrDefault();
Console.WriteLine(firstNumOrDefault);
}

Result

FirstOrDefault - Condition

This sample uses FirstOrDefault to return the first product whose ProductID is 789 as a single
Product object, unless there is no match, in which case null is returned.

public void Linq62()


{
List<Product> products = GetProductList();
Product product789 = products.FirstOrDefault(p => p.ProductID == 789);
Console.WriteLine("Product 789 exists: {0}", product789 != null);
}
Result

Product 789 exists: False

ElementAt

This sample uses ElementAt to retrieve the second number greater than 5 from an array.

public void Linq64()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int fourthLowNum = (
from n in numbers
where n > 5
select n)

.ElementAt(1); // second number is index 1 because sequences use 0-


based indexing

Console.WriteLine("Second number > 5: {0}", fourthLowNum);


}

Result

Second number > 5: 8

Generation Operators

Range

This sample uses Range to generate a sequence of numbers from 100 to 149 that is used to find
which numbers in that range are odd and even.

public void Linq65()


{
var numbers =
from n in Enumerable.Range(100, 50)
select new { Number = n, OddEven = n % 2 == 1 ? "odd" : "even" };

foreach (var n in numbers)


{
Console.WriteLine("The number {0} is {1}.", n.Number, n.OddEven);
}
}

Result

The number 100 is even.


The number 101 is odd.
The number 102 is even.

Repeat

This sample uses Repeat to generate a sequence that contains the number 7 ten times.

public void Linq66()


{
var numbers = Enumerable.Repeat(7, 10);
foreach (var n in numbers)
{
Console.WriteLine(n);
}
}

Result

7
7
7

Quantifiers

Any - Simple

This sample uses Any to determine if any of the words in the array contain the substring 'ei'.

public void Linq67()


{
string[] words = { "believe", "relief", "receipt", "field" };
bool iAfterE = words.Any(w => w.Contains("ei"));

Console.WriteLine("There is a word that contains in the list that contains


'ei': {0}", iAfterE);
}

Result

There is a word that contains in the list that contains 'ei': True

Any - Grouped

This sample uses Any to return a grouped a list of products only for categories that have at least
one product that is out of stock.

public void Linq69()


{
List<Product> products = GetProductList();
var productGroups =
from p in products
group p by p.Category into g
where g.Any(p => p.UnitsInStock == 0)
select new { Category = g.Key, Products = g };

ObjectDumper.Write(productGroups, 1);
}

Result

Category=Condiments     Products=...
  Products: ProductID=3   ProductName=Aniseed Syrup       Category=Condiments   
UnitPrice=10.0000       UnitsInStock=13

All - Simple

This sample uses All to determine whether an array contains only odd numbers.

public void Linq70()


{ int[] numbers = { 1, 11, 3, 19, 41, 65, 19 };
bool onlyOdd = numbers.All(n => n % 2 == 1);
Console.WriteLine("The list contains only odd numbers: {0}", onlyOdd);
}

Result

The list contains only odd numbers: True

All - Grouped

This sample uses All to return a grouped a list of products only for categories that have all of
their products in stock.

public void Linq72()


{
List<Product> products = GetProductList();
var productGroups =
from p in products
group p by p.Category into g
where g.All(p => p.UnitsInStock > 0)
select new { Category = g.Key, Products = g };
ObjectDumper.Write(productGroups, 1);
}

Result
Category=Beverages      Products=...
  Products: ProductID=1 
ProductName=Chai        Category=Beverages      UnitPrice=18.0000       UnitsInStock=39
  Products: ProductID=2   ProductName=Chang     
Category=Beverages      UnitPrice=19.0000       UnitsInStock=17

Aggregator Operators

Count - Simple

This sample uses Count to get the number of unique factors of 300.

public void Linq73()


{
int[] factorsOf300 = { 2, 2, 3, 5, 5 };

int uniqueFactors = factorsOf300.Distinct().Count();

Console.WriteLine("There are {0} unique factors of 300.", uniqueFactors);


}

Result

There are 3 unique factors of 300.

Count - Conditional

This sample uses Count to get the number of odd ints in the array.

public void Linq74()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int oddNumbers = numbers.Count(n => n % 2 == 1);

Console.WriteLine("There are {0} odd numbers in the list.", oddNumbers);


}

Result

There are 5 odd numbers in the list.

Count - Nested

This sample uses Count to return a list of customers and how many orders each has.
public void Linq76()
{
List<Customer> customers = GetCustomerList();

var orderCounts =
from c in customers
select new { c.CustomerID, OrderCount = c.Orders.Count() };

ObjectDumper.Write(orderCounts);
}

Result

Count - Grouped

This sample uses Count to return a list of categories and how many products each have.

public void Linq77()


{
List<Product> products = GetProductList();

var categoryCounts =
from p in products
group p by p.Category into g
select new { Category = g.Key, ProductCount = g.Count() };

ObjectDumper.Write(categoryCounts
}

Result

Category=Beverages ProductCount=12
Category=Condiments ProductCount=12
Category=Produce ProductCount=5
Category=Meat/Poultry ProductCount=6
Category=Seafood ProductCount=12
Category=Dairy Products ProductCount=10
ProductCount=13
Category=Confections ProductCount=7
Category=Grains/Cereals

Sum - Simple

This sample uses Sum to get the total of the numbers in an array.

public void Linq78()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

double numSum = numbers.Sum();

Console.WriteLine("The sum of the numbers is {0}.", numSum);


}

Result

The sum of the numbers is 45.

Sum - Projection

This sample uses Sum to get the total number of characters of all words in the array.

public void Linq79()


{
string[] words = { "cherry", "apple", "blueberry" };

double totalChars = words.Sum(w => w.Length);

Console.WriteLine("There are a total of {0} characters in these words.",


totalChars);
}

Result

There are a total of 20 characters in these words.

Sum - Grouped

This sample uses Sum to get the total units in stock for each product category.

public void Linq80()


{
List<Product> products = GetProductList();

var categories =
from p in products
group p by p.Category into g
select new { Category = g.Key, TotalUnitsInStock = g.Sum(p =>
p.UnitsInStock) };

ObjectDumper.Write(categories);
}

Result

Category=Beverages TotalUnitsInStock=559
Category=Condiments TotalUnitsInStock=507
Category=Produce TotalUnitsInStock=100
Category=Meat/Poultry TotalUnitsInStock=165
Category=Seafood TotalUnitsInStock=701
Category=Dairy Products TotalUnitsInStock=393
TotalUnitsInStock=386
Category=Confections TotalUnitsInStock=308
Category=Grains/Cereals

Min - Simple

This sample uses Min to get the lowest number in an array.

public void Linq81()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int minNum = numbers.Min();

Console.WriteLine("The minimum number is {0}.", minNum);


}

Result

The minimum number is 0.

Min - Projection

This sample uses Min to get the length of the shortest word in an array.

public void Linq82()


{
string[] words = { "cherry", "apple", "blueberry" };

int shortestWord = words.Min(w => w.Length);

Console.WriteLine("The shortest word is {0} characters long.",


shortestWord);
}

Result

The shortest word is 5 characters long.

Min - Grouped

This sample uses Min to get the cheapest price among each category's products.

public void Linq83()


{
List<Product> products = GetProductList();
var categories =
from p in products
group p by p.Category into g
select new { Category = g.Key, CheapestPrice = g.Min(p =>
p.UnitPrice) };

ObjectDumper.Write(categories);
}

Result

Category=Beverages CheapestPrice=4.5000
Category=Condiments CheapestPrice=10.0000
Category=Produce CheapestPrice=10.0000
Category=Meat/Poultry CheapestPrice=7.4500
Category=Seafood CheapestPrice=6.0000
Category=Dairy Products CheapestPrice=2.5000
Category=Confections CheapestPrice=9.2000
Category=Grains/Cereals CheapestPrice=7.0000

Min - Elements

This sample uses Min to get the products with the cheapest price in each category.

public void Linq84()


{
List<Product> products = GetProductList();

var categories =
from p in products
group p by p.Category into g
let minPrice = g.Min(p => p.UnitPrice)
select new { Category = g.Key, CheapestProducts = g.Where(p =>
p.UnitPrice == minPrice) };

ObjectDumper.Write(categories, 1);
}

Result

Category=Beverages      CheapestProducts=...
  CheapestProducts:
ProductID=24  ProductName=Guaraná Fantástica  Category=Beverages      UnitPrice=4.500
0        UnitsInStock=20

Max - Simple
This sample uses Max to get the highest number in an array.

public void Linq85()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int maxNum = numbers.Max();

Console.WriteLine("The maximum number is {0}.", maxNum);


}

Result

The maximum number is 9.

Max - Projection

This sample uses Max to get the length of the longest word in an array.

public void Linq86()


{
string[] words = { "cherry", "apple", "blueberry" };

int longestLength = words.Max(w => w.Length);

Console.WriteLine("The longest word is {0} characters long.",


longestLength);
}

Result

The longest word is 9 characters long.

Max - Grouped

This sample uses Max to get the most expensive price among each category's products.

public void Linq87()


{
List<Product> products = GetProductList();

var categories =
from p in products
group p by p.Category into g
select new { Category = g.Key, MostExpensivePrice = g.Max(p =>
p.UnitPrice) };

ObjectDumper.Write(categories);
}
Result

Category=Beverages MostExpensivePrice=263.5000
Category=Condiments MostExpensivePrice=43.9000
Category=Produce MostExpensivePrice=53.0000
Category=Meat/Poultry MostExpensivePrice=123.7900
Category=Seafood MostExpensivePrice=62.5000
Category=Dairy Products MostExpensivePrice=55.0000
MostExpensivePrice=81.0000
Category=Confections MostExpensivePrice=38.0000
Category=Grains/Cereals

Max - Elements

This sample uses Max to get the products with the most expensive price in each category.

public void Linq88()


{
List<Product> products = GetProductList();

var categories =
from p in products
group p by p.Category into g
let maxPrice = g.Max(p => p.UnitPrice)
select new { Category = g.Key, MostExpensiveProducts = g.Where(p =>
p.UnitPrice == maxPrice) };

ObjectDumper.Write(categories, 1);
}

Result

Category=Beverages      MostExpensiveProducts=...
  MostExpensiveProducts: ProductID=38     ProductName=Côte de Blaye 
Category=Beverages      UnitPrice=263.5000      UnitsInStock=17

Average - Simple

This sample uses Average to get the average of all numbers in an array.

public void Linq89()


{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

double averageNum = numbers.Average();


Console.WriteLine("The average number is {0}.", averageNum);
}

Result

The average number is 4.5.

Average - Projection

This sample uses Average to get the average length of the words in the array.

public void Linq90()


{
string[] words = { "cherry", "apple", "blueberry" };

double averageLength = words.Average(w => w.Length);

Console.WriteLine("The average word length is {0} characters.",


averageLength);
}

Result

The average word length is 6.66666666666667 characters.

Average - Grouped

This sample uses Average to get the average price of each category's products.

public void Linq91()


{
List<Product> products = GetProductList();

var categories =
from p in products
group p by p.Category into g
select new { Category = g.Key, AveragePrice = g.Average(p =>
p.UnitPrice) };

ObjectDumper.Write(categories);
}

Result

Category=Beverages AveragePrice=37.979166666666666666666666667
Category=Condiments AveragePrice=23.0625
Category=Produce AveragePrice=32.3700
Category=Meat/Poultry AveragePrice=54.006666666666666666666666667
Category=Seafood AveragePrice=20.6825
Category=Dairy Products AveragePrice=28.7300
AveragePrice=25.1600
Category=Confections AveragePrice=20.2500
Category=Grains/Cereals

Aggregate - Simple

This sample uses Aggregate to create a running product on the array that calculates the total
product of all elements.

public void Linq92()


{
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };

double product = doubles.Aggregate((runningProduct, nextFactor) =>


runningProduct * nextFactor);

Console.WriteLine("Total product of all numbers: {0}", product);


}

Result

Total product of all numbers: 88.33081

Aggregate - Seed

This sample uses Aggregate to create a running account balance that subtracts each withdrawal
from the initial balance of 100, as long as the balance never drops below 0

public void Linq93()


{
double startBalance = 100.0;

int[] attemptedWithdrawals = { 20, 10, 40, 50, 10, 70, 30 };

double endBalance =
attemptedWithdrawals.Aggregate(startBalance,
(balance, nextWithdrawal) =>
((nextWithdrawal <= balance) ? (balance - nextWithdrawal) :
balance));

Console.WriteLine("Ending balance: {0}", endBalance);


}

Result

Ending balance: 20
Miscellaneous Operators

Concat - 1

This sample uses Concat to create one sequence that contains each array's values, one after the
other.

public void Linq94()


{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };

var allNumbers = numbersA.Concat(numbersB);

Console.WriteLine("All numbers from both arrays:");


foreach (var n in allNumbers)
{
Console.WriteLine(n);
}
}

Result

All numbers from both arrays:


0
2
4
5
6
8
9
1
3
5
7
8

Concat - 2

This sample uses Concat to create one sequence that contains the names of all customers and
products, including any duplicates.

public void Linq95()


{
List<Customer> customers = GetCustomerList();
List<Product> products = GetProductList();
var customerNames =
from c in customers
select c.CompanyName;
var productNames =
from p in products
select p.ProductName;

var allNames = customerNames.Concat(productNames);

Console.WriteLine("Customer and product names:");


foreach (var n in allNames)
{
Console.WriteLine(n);
}
}

Result

Customer and product names:


Alfreds Futterkiste
Ana Trujillo Emparedados y helados
Antonio Moreno TaquerÃa
Around the Horn
Berglunds snabbköp

EqualAll - 1

This sample uses EqualAll to see if two sequences match on all elements in the same order.

public void Linq96()


{
var wordsA = new string[] { "cherry", "apple", "blueberry" };
var wordsB = new string[] { "cherry", "apple", "blueberry" };
bool match = wordsA.SequenceEqual(wordsB);
Console.WriteLine("The sequences match: {0}", match);
}

Result

The sequences match: True

EqualAll - 2

This sample uses EqualAll to see if two sequences match on all elements in the same order.

public void Linq97()


{
var wordsA = new string[] { "cherry", "apple", "blueberry" };
var wordsB = new string[] { "apple", "blueberry", "cherry" };
bool match = wordsA.SequenceEqual(wordsB);
Console.WriteLine("The sequences match: {0}", match);
}

Result

The sequences match: False

Custom Sequence Operators

Combine

This sample calculates the dot product of two integer vectors. It uses a user-created sequence
operator, Combine, to calculate the dot product, passing it a lambda function to multiply two
arrays, element by element, and sum the result.

public static class CustomSequenceOperators


{
    public static IEnumerable Combine(this IEnumerable first, IEnumerable
second,
    Func func) {
        using (IEnumerator e1 = first.GetEnumerator(), e2 =
second.GetEnumerator())
        {
            while (e1.MoveNext() && e2.MoveNext()) {
                yield return func(e1.Current, e2.Current);
            }
        }
    }
}

public void Linq98() {            


    int[] vectorA = { 0, 2, 4, 5, 6 };
    int[] vectorB = { 1, 3, 5, 7, 8 };
    
    int dotProduct = vectorA.Combine(vectorB, (a, b) => a * b).Sum();
    
    Console.WriteLine("Dot product: {0}", dotProduct);
}

Result

Dot product: 109

Query Execution

Deferred Execution

The following sample shows how query execution is deferred until the query is enumerated at a
foreach statement.
public void Linq99()
{
// Sequence operators form first-class queries that
// are not executed until you enumerate over them.

int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int i = 0;
var q =
from n in numbers
select ++i;

// Note, the local variable 'i' is not incremented


// until each element is evaluated (as a side-effect):
foreach (var v in q)
{
Console.WriteLine("v = {0}, i = {1}", v, i);
}
}

Result

v = 1, i = 1
v = 2, i = 2
v = 3, i = 3
v = 4, i = 4
v = 5, i = 5
v = 6, i = 6
v = 7, i = 7
v = 8, i = 8
v = 9, i = 9
v = 10, i = 10

Immediate Execution

The following sample shows how queries can be executed immediately with operators such as
ToList().

public void Linq100()


{
// Methods like ToList() cause the query to be
// executed immediately, caching the results.

int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int i = 0;
var q = (
from n in numbers
select ++i)
.ToList();

// The local variable i has already been fully


// incremented before we iterate the results:
foreach (var v in q)
{
Console.WriteLine("v = {0}, i = {1}", v, i);
}
}

Result

v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10

Query Reuse

The following sample shows how, because of deferred execution, queries can be used again after
data changes and will then operate on the new data.

public void Linq101()


{
// Deferred execution lets us define a query once
// and then reuse it later after data changes.

int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };


var lowNumbers =
from n in numbers
where n <= 3
select n;

Console.WriteLine("First run numbers <= 3:");


foreach (int n in lowNumbers)
{
Console.WriteLine(n);
}

for (int i = 0; i < 10; i++)


{
numbers[i] = -numbers[i];
}

// During this second run, the same query object,


// lowNumbers, will be iterating over the new state
// of numbers[], producing different results:
Console.WriteLine("Second run numbers <= 3:");
foreach (int n in lowNumbers)
{
Console.WriteLine(n);
}
}

Result

First run numbers <= 3:


1
3
2
0
Second run numbers <= 3:
-5
-4
-1
-3
-9
-8
-6
-7
-2
0

GetProductList code

GetProductList() is a routine used by many of the samples. It is defined as:

public List GetProductList() { productList = new List { { ProductID = 1, ProductName = "Chai",


Category = "Beverages", UnitPrice = 18.0000M, UnitsInStock = 39 }, { ProductID = 2,
ProductName = "Chang", Category = "Beverages", UnitPrice = 19.0000M, UnitsInStock = 17 }}

Join Operators

Cross Join

This sample shows how to efficiently join elements of two sequences based on equality between
key expressions over the two.

public void Linq102()


{
string[] categories = new string[]{
"Beverages",
"Condiments",
"Vegetables",
"Dairy Products",
"Seafood" };
List<Product> products = GetProductList();
var q =
from c in categories
join p in products on c equals p.Category
select new { Category = c, p.ProductName };

foreach (var v in q)
{
Console.WriteLine(v.ProductName + ": " + v.Category);
}
}

Result

Chai: Beverages
Chang: Beverages
Guaraná Fantástica: Beverages
Sasquatch Ale: Beverages
Steeleye Stout: Beverages

Group Join

Using a group join you can get all the products that match a given category bundled as a
sequence.

public void Linq103()


{
string[] categories = new string[]{
"Beverages",
"Condiments",
"Vegetables",
"Dairy Products",
"Seafood" };

List<Product> products = GetProductList();


var q =
from c in categories
join p in products on c equals p.Category into ps
select new { Category = c, Products = ps };

foreach (var v in q)
{
Console.WriteLine(v.Category + ":");
foreach (var p in v.Products)
{
Console.WriteLine(" " + p.ProductName);
}
}
}
Result

Beverages:
Chai
Chang
Guaraná Fantástica
Sasquatch Ale

Cross Join with Group Join

The group join operator is more general than join, as this slightly more verbose version of the
cross join sample shows.

public void Linq104()

string[] categories = new string[]{


"Beverages",
"Condiments",
"Vegetables",
"Dairy Products",
"Seafood" };

List<Product> products = GetProductList();


var q =
from c in categories
join p in products on c equals p.Category into ps
from p in ps
select new { Category = c, p.ProductName };
foreach (var v in q)
{
Console.WriteLine(v.ProductName + ": " + v.Category);
}
}

Result

Chai: Beverages
Chang: Beverages
Guaraná Fantástica: Beverages
Sasquatch Ale: Beverages

Left Outer Join

A so-called outer join can be expressed with a group join. A left outer joinis like a cross join,
except that all the left hand side elements get included at least once, even if they don't match any
right hand side elements. Note how Vegetablesshows up in the output even though it has no
matching products.

public void Linq105()

{
string[] categories = new string[]{
"Beverages",
"Condiments",
"Vegetables",
"Dairy Products",
"Seafood" };
List<Product> products = GetProductList();
var q =
from c in categories
join p in products on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
select new { Category = c, ProductName = p == null ? "(No products)" :
p.ProductName };

foreach (var v in q)
{
Console.WriteLine(v.ProductName + ": " + v.Category);
}
}

Result

Chai: Beverages
Chang: Beverages
Guaraná Fantástica: Beverages
Sasquatch Ale: Beverages

You might also like