程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> LINQ的經典例子-Where,Select、SelectMany、SkipWhile子句中使用數組索引

LINQ的經典例子-Where,Select、SelectMany、SkipWhile子句中使用數組索引

編輯:.NET實例教程
Where 子句的用法 

我們除了可以如下方式書寫帶Where子句的LINQ外: 

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

還可以對數組(所有實現了IEnumerable接口的對象都可以)的實體使用 Where 擴展方法。

把一個查詢語句寫成多個擴展函數的方式,這其實是編譯器處理查詢語句的方法,比如下面的查詢語句: 

int[] arr = new int[] { 8, 5, 89, 3, 56, 4, 1, 58 };
var m = from n in arr where n < 5 orderby n select n; 

編譯器在編譯後,替我們產生的代碼等價於如下的代碼: 

IOrderedSequence m = arr.Where(delegate (int n) {
    return (n < 5);
}).OrderBy(delegate (int n) {
    return n;
}); 

下面我們來看一個使用Where擴展方法的例子:

我們有一個字符串數組,一次是0到9的英文單詞,我們查詢出這10個字符的長度比它所在數組的位置 這兩個數字比較小的英文單詞.

這個查詢可能有些繞口,你可以先看下面這些代碼:

public static void LinqDemo01()
{
    string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
    var shortDigits = digits.Where((dd, aa) => dd.Length < aa);
    Console.WriteLine("Short digits:");
    foreach (var d in shortDigits)
        Console.WriteLine("The Word {0} is shorter than its value.", d);


輸出結果: 

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. 

下面我們就來分析上述代碼中最核心的代碼:

digits.Where((dd, aa) => dd.Length < aa);

這行代碼都趕了些什麼?

1、Where子句其實是用擴展方法來實現的 

如果你對擴展方法不熟悉,請先看我之前的幾篇博客:

C#3.0 中的擴展方法 (Extension Methods) 

C#3.0 中使用擴展方法來擴展接口 

Orcas Beta1 對多個同名擴展方法的處理邏輯 

微軟替我們實現的 Where 子句對應的擴展函數實際是如下的定義: 

namespace System.Linq
{
    public delegate TResult Func(TArg0 arg0, TArg1 arg1); 
    public static class Enumerable
    {
        public static IEnumerable Where(this IEnumerable source, Func predicate);
        public static IEnumerable Where(this IEnumerable source, Func predicate);
    }


其中紅色字體的那個擴展函數,就是我們上面代碼實際使用的擴展函數。

我們這個擴展函數參數:Func predicate 的定義看上面代碼的綠色delegate 代碼。

2、Where 子句參數書寫的是Lambda 表達式 

如果你不清楚什麼是Lambda 表達式,你可以參看我之前的博客:

C# 3.0 的Lambda表達式(Lambda Expressions) 

(dd, aa) => dd.Length < aa 就相當於 C# 2.0 的匿名函數。

LINQ中所有關鍵字比如 Select,SelectMany, Count, All 等等其實都是用擴展方法來實現的。上面的用法同樣也適用於這些關鍵字子句。 

3、這個Where子句中Lambda 表達式第二個參數是數組索引,我們可以在Lambda 表達式內部使用數組索引。來做一些復雜的判斷。 

具有數組索引的LINQ關鍵字除了Where還以下幾個Select,SelectMany, Count, Al


我們下面就來依次舉例 

Select 子句使用數組索引的例子 

下面代碼有一個整數數組,我們找出這個數字是否跟他在這個數組的位置一樣 

public static void LinqDemo01()
{
    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委托定義如下: 

public static IEnumerable Select(this IEnumerable source, Func selector); 

public delegate TResult Func(TArg0 arg0, TArg1 arg1); 

SelectMany 子句使用數組索引的例子 

幾個句子組成的數組,我們希望把這幾個句子拆分成單詞,並顯示每個單詞在那個句子中。查詢語句如下: 

public static void Demo01()
{
    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 是找到一個滿足條件的,然後後面的數據全部返回。 

下面例子返回一個整數數組中,這個整數比他自身在這個數組的位置大於等於的第一個位置以及之後的數據。 

public static 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);


輸出結果:

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


First 、FirstOrDefault、Any、All、Count 子句 

注意:

101 LINQ Samples  中 First - Indexed、FirstOrDefault - Indexed、 Any - Indexed、All - Indexed、Count - Indexed 這五個例子在 Orcas Beta1中已經不在可用,即下面代碼是錯誤的。

public void Linq60() {
    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
  &n
bsp; 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
       &n
bsp;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);


參考資料:



本文來自CSDN博客,轉載請標明出處:http://blog.csdn.Net/dz45693/archive/2009/12/17/5028035.ASPx
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved