LinQ 扩展函数的应用
xxx.Where((aa, bb) => aa.Length < bb);
明白以上代码是什么意思?(大家都是谈初学,高手浏览即可)
1、Where子句其实是用扩展方法来实现的
MS实现的 Where 子句对应的扩展函数是如下的定义:
namespace System.Linq
{
public delegate TResult Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1);
public static class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
}
}
其中红色字体的那个扩展函数,就是我们上面代码实际使用的扩展函数。
我们这个扩展函数参数:Func<TSource, int, bool> predicate 的定义看上面代码的绿色delegate 代码。
2、Where 子句参数书写的是Lambda 表达式
((aa, bb) => aa.Length < bb); 就相当于 C# 2.0 的匿名函数。
LINQ中所有关键字比如 Select,SelectMany, Count, All 等等其实都是用扩展方法来实现的。上面的用法同样也适用于这些关键字子句。
3、这个Where子句中Lambda 表达式第二个参数是数组索引,我们可以在Lambda 表达式内部使用数组索引。来做一些复杂的判断。
具有数组索引的LINQ关键字除了Where还以下几个Select,SelectMany, Count, All
我们下面就来依次举例
Select 子句使用数组索引的例子
下面代码有一个整数数组,我们找出这个数字是否跟他在这个数组的位置一样
{
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);
}
输出结果:
Number: In-place?
5: False
4: False
1: False
3: True
9: False
8: False
6: True
7: True
2: False
0: False
其中我们用到的这个Select子句对应的扩展函数定义,以及其中Func<TSource, int, TResult>委托定义如下:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector);
public delegate TResult Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1);
SelectMany 子句使用数组索引的例子
几个句子组成的数组,我们希望把这几个句子拆分成单词,并显示每个单词在那个句子中。查询语句如下:
{
string[] text = { "Albert was here",
"Burke slept late",
"Connor is happy" };
var tt = text.SelectMany((s, index) => from ss in s.Split(' ') select new { Word = ss, Index = index });
foreach (var n in tt)
Console.WriteLine("{0}:{1}", n.Word,n.Index);
}
结果:
Albert:0
was:0
here:0
Burke:1
slept:1
late:1
Connor:2
is:2
happy:2
SkipWhile 子句使用数组索引的例子
SkipWhile 意思是一直跳过数据,一直到满足表达式的项时,才开始返回数据,而不管之后的项是否仍然满足表达式,需要注意他跟Where是不一样的,Where是满足条件的记录才返回,SkipWhile 是找到一个满足条件的,然后后面的数据全部返回。
下面例子返回一个整数数组中,这个整数比他自身在这个数组的位置大于等于的第一个位置以及之后的数据。
{
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);
}
输出结果:
All elements starting from first element less than its position:
1
3
9
8
6
7
2
0
First 、FirstOrDefault、Any、All、Count 子句
注意:
101 LINQ Samples 中 First - Indexed、FirstOrDefault - Indexed、 Any - Indexed、All - Indexed、Count - Indexed 这五个例子在 Orcas Beta1中已经不在可用,即下面代码是错误的。
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int evenNum = numbers.First((num, index) => (num % 2 == 0) && (index % 2 == 0));
Console.WriteLine("{0} is an even number at an even position within the list.", evenNum);
}
public void Linq63() {
double?[] doubles = { 1.7, 2.3, 4.1, 1.9, 2.9 };
double? num = doubles.FirstOrDefault((n, index) => (n >= index - 0.5 && n <= index + 0.5));
if (num != null)
Console.WriteLine("The value {1} is within 0.5 of its index position.", num);
else
Console.WriteLine("There is no number within 0.5 of its index position.", num);
}
public void Linq68() {
int[] numbers = { -9, -4, -8, -3, -5, -2, -1, -6, -7 };
bool negativeMatch = numbers.Any((n, index) => n == -index);
Console.WriteLine("There is a number that is the negative of its index: {0}", negativeMatch);
}
public void Linq71() {
int[] lowNumbers = { 1, 11, 3, 19, 41, 65, 19 };
int[] highNumbers = { 7, 19, 42, 22, 45, 79, 24 };
bool allLower = lowNumbers.All((num, index) => num < highNumbers[index]);
Console.WriteLine("Each number in the first list is lower than its counterpart in the second list: {0}", allLower);
}
public void Linq75() {
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddEvenMatches = numbers.Count((n, index) => n % 2 == index % 2);
Console.WriteLine("There are {0} numbers in the list whose odd/even status " +
"matches that of their position.", oddEvenMatches);
}
要实现这个功能,可以用Where 子句,如下:
public static void Linq60()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int evenNum = numbers.Where((num,index) =>( num % 2 == 0 && index %2 == 0) ).First();
Console.WriteLine("{0} is an even number at an even position within the list.", evenNum);
}
public static void Linq63()
{
double?[] doubles = { 1.7, 2.3, 4.1, 1.9, 2.9 };
double? num = doubles.Where((n, index) => (n >= index - 0.5 && n <= index + 0.5)).FirstOrDefault();
if (num != null)
Console.WriteLine("The value {1} is within 0.5 of its index position.", num);
else
Console.WriteLine("There is no number within 0.5 of its index position.", num);
}
public static void Linq68()
{
int[] numbers = { -9, -4, -8, -3, -5, -2, -1, -6, -7 };
bool negativeMatch = numbers.Where((n, index) => n == -index).Any();
Console.WriteLine("There is a number that is the negative of its index: {0}", negativeMatch);
}
public static void Linq71()
{
int[] lowNumbers = { 1, 11, 3, 19, 41, 65, 19 };
int[] highNumbers = { 7, 19, 42, 22, 45, 79, 24 };
bool allLower = lowNumbers.Where((num, index) => num < highNumbers[index]).All(n => true);
Console.WriteLine("Each number in the first list is lower than its counterpart in the second list: {0}", allLower);
}
public static void Linq75()
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddEvenMatches = numbers.Where((n, index) => n % 2 == index % 2).Count();
Console.WriteLine("There are {0} numbers in the list whose odd/even status " +
"matches that of their position.", oddEvenMatches);
}