LINQ笔记&实例
LINQ:语言继承查询
限制运算符 Where
where语句的基本示例
int[] numbers = {5,4,1,3,9,8,6,7,2,0};
var lowNums = from num in numbers
where num < 5
select num; // 只选择小于5的数字
筛选符合属性条件的元素
var soldOutProducts = from prod in products
where prod.UnitsInStock == 0
select prod; // 从集合中选出符合属性的元素
用多个条件筛选元素
var expensiveInStockProducts = from prod in products
where prod.UnitsInStock > 0 && prod.UnitPrice > 3.00M
select prod; // 从集合中选出符合上述两个条件的元素
基于元素在列表中位置的筛选
string[] digits = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
var shortDigits = digits.Where((digit,index) => digit.Length < index);
// 其中,index为元素的位置下标(从0开始),digit为digits的子元素。
以…开始
使用AutoSuggestBox
控件
Xaml:
<AutoSuggestBox Name="MyAutoSuggestBox"
QueryIcon="Find"
PlaceholderText="Search"
TextChanged="MyAutoSuggestBox_TextChanged"/>
C#
private string[] selectionItems = new string[] {"Ferdinand", "Nigel", "Tag",...};
private void MyAutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs e)
{
var autoSuggestBox = (AutoSuggestBox)sender;
var fileterd = selectionItems.Where(p => p.StartWith(AutoSuggestBox.Text)).ToArray();
autoSuggestBox.ItemSource = filtered;
}
投影(转换)运算符 Select
以下的例子展示了如何用select修改输入的元素序列。
int[] numbers = {5,4,1,3,9,8,6,7,2,0};
var numsPlusOne = from n in numbers
select n+1;
选择一个单独的属性
var productNames = from p in products
select p.ProductName; // 选择了p的ProductName属性
用select
进行一些变换
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]; // 用数字序列的元素作为下标选择单词序列中的元素
选择匿名类型或元组
注意:创建新类型的时候,需要使用
new
关键字
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };
var upperLowerWords = from w in words
select new { Upper = w.ToUpper(), Lower = w.ToLower() };
// 生成的Upper和Lower里面分别是这些单词的大写和小写版本
// 使用元组的方法(从C#7开始)
var upperLowerWords = from w in words
select new { Upper: w.ToUpper(), Lower: w.ToLower() };
使用select
创建新类型
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)};
// 创建了两个类型:
// Digit:对应数字的单词序列
// Even:偶数序列
选择属性的子集
我还没试,Try.NET坏了…😭
var productInfos = from p in products
select (p.ProductName, p.Category, Price: p.UnitPrice);
Console.WriteLine("Product Info:");
foreach (var productInfo in productInfos)
{
Console.WriteLine($"{productInfo.ProductName} is in the category {productInfo.Category} and costs {productInfo.Price} per unit.");
}
用元素的index
对其进行选择
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var numsInPlace = numbers.Select((num, index) => (Num: num, InPlace: (num == index)));
// 得到的numsInPlace中有Num和InPlace,其中InPlace为num==index的值
在多输入序列中进行选择
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 (a, b); // 符合条件的(a,b)对(pairs)
Console.WriteLine("Pairs where a < b:");
foreach (var pair in pairs)
{
Console.WriteLine($"{pair.a} is less than {pair.b}");
// 把所有的a和所有的b逐个进行比较
}
在相关的输入序列中进行选择
var orders = from c in customers
from o in c.Orders
where o.Total < 500.00M
select (c.CustomerID, o.OrderID, o.Total);
// cutomers -> c:顾客
// c -> c.o:订单(与c相关联)
// c.o -> o:订单信息
带有Where的符合选择
var orders = from c in customers
from o in c.Orders
where o.OrderDate >= new DateTime(1998, 1, 1)
select (c.CustomerID, o.OrderID, o.OrderDate);
Query Syntax 查询语法(分区运算符)
Take
n.Take(n);
获取前n个元素
int[] numbers={5,4,3,2,1};
var first3Numbers = numbers.Take(3); // First3Numbers是一个集合,有3个数
Take
也可以嵌套到其它查询语句中
var first3WAOrders = (
from customer in customers
from order in cutomer.Orders
where customer.Region == "WA"
select (customer.CustomerID, order.OrderID, order.OrderDate)
.Take(3);
) // 得到前3个
Skip
n.Skip(n)
跳过前n个元素
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var allButFirst4Numbers = numbers.Skip(4);
先查询,再在结果中跳过
var waOrders = from cust in customers
from order in cust.Orders
where cust.Region == "WA"
select (cust.CustomerID, order.OrderID, order.OrderDate);
var allButFirst2Orders = waOrders.Skip(2); // 查询完毕后,从查询结果中跳过前2个结果
TakeWhile
理解为While
循环下的Take()
。一旦不符合条件就停止。
int[] numbers = {5,4,1,3,9,8,6,7,2,0};
var firstNumbersLessThan6 = numbers.TakeWhile(n => n<6);
// 从开始一直Take(),直到n<6的条件不成立
用index
作为条件的TakeWhile
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
SkipWhile
以下例子只显示分数小于80的成绩。
int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
IEnumerable<int> lowerGrades =
grades
.OrderByDescending(grade => grade)
.SkipWhile(grade => grade >= 80);
Console.WriteLine("All grades below 80:");
foreach (int grade in lowerGrades)
{
Console.WriteLine(grade);
}
// This code produces the following output:
// All grades below 80:
// 70
// 59
// 56
使用n
和index
进行筛选
int[] amounts = { 5000, 2500, 9000, 8000,
6500, 4000, 1500, 5500 };
IEnumerable<int> query =
amounts.SkipWhile((amount, index) => amount > index * 1000);
foreach (int amount in query)
{
Console.WriteLine(amount);
}
// This code produces the following output:
// 4000
// 1500
// 5500
排序运算符
orderby 升序
升序:0,1,2,…
使用orderby
根据宠物年龄进行升序排序
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
// Sort the Pet objects in the array by Pet.Age.
IEnumerable<Pet> query =
pets.AsQueryable().OrderBy(pet => pet.Age);
foreach (Pet pet in query)
Console.WriteLine($"{pet.Name} - {pet.Age}");
}
// This code produces the following output:
// Whiskers - 1
// Boots - 4
// Barley - 8
orderby descending
使用orderby
和descending
关键字对数字进行降序排序。
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };
var sortedDoubles = from d in doubles
orderby d descending // 注意descending的用法
select d;
Console.WriteLine("The doubles from highest to lowest:");
序列操作
EqualAll
如果两个序列相同,返回True
var wordsA = new string[] { "cherry", "apple", "blueberry" };
var wordsB = new string[] { "cherry", "apple", "blueberry" };
bool match = wordsA.SequenceEqual(wordsB);
Console.WriteLine($"The sequences match: {match}"); //True
// 如果以上两个序列中的元素顺序进行了调换,输出值则为False
Zip
int[] vectorA = { 0, 2, 4, 5, 6 };
int[] vectorB = { 1, 3, 5, 7, 8 };
int dotProduct = vectorA.Zip(vectorB, (a, b) => a * b).Sum();
// 把A中的元素和B中的对应元素进行操作。
// Sum()为求和
Console.WriteLine($"Dot product: {dotProduct}");
// Dot product:109
Query(查询)执行模式
懒惰执行
如果数据经常变化,可以考虑使用“懒惰查询”,需要时再进行查询。
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int i = 0;
var q = from n in numbers
select ++i; //i: 0 → 1
// Note, the local variable 'i' is not incremented
// until each element is evaluated (as a side-effect):
// 直到每个值被使用时才执行++i
foreach (var v in q)
{
Console.WriteLine($"v = {v}, i = {i}");
// ++i在这里才被执行并存入v中。
// 这里的i是原来的i(int i=0时定义的)
}
如果把foreach
再完整执行一遍,v
和i
的值将会到达20
急迫执行
当数据不会变时使用“急迫执行”,因为再次查询数据也不会变。
// Methods like ToList() cause the query to be
// executed immediately, caching the results.
// 类似ToList()的方法可以使query立即执行。
int[] numbers = { 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:
// 在输出结果之前,++i已经全部执行完了
foreach (var v in q)
{
Console.WriteLine($"v = {v}, i = {i}");
}
如果把foreach
再完整执行一遍,i
的值仍然全为10,v
的值也不变