LINQ語法簡介 - 3

by vivid 21. 三月 2018 03:56

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:
N180319302
出刊日期: 2018/3/21

在這篇文章中,將延續《LINQ語法簡介 - 1》與《LINQ語法簡介 - 2》文章的情境,介紹常用的LINQ運算子(Operator),以透過更簡易的語法來查詢陣列或集合中的內容。

 

Aggregation 運算子 - Aggregate

「Aggregate」運算子用於執行累積運算。例如我們想要撰寫程式碼,計算出「1+2+3+4+5」數學式的總合,可以使用以下程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Aggregate( ( i , j ) => i + j );
Console.WriteLine( $"Result : {result}" ); // Result : 15

讓我們換個寫法來研究一下「Aggregate」的運作,修改程式碼如下,將每次執行匿名方法時當下的「i」與「j」值輸出到主控台:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Aggregate( ( i , j ) => {
   Console.WriteLine( $" {i} - {j}" );
   return i + j;
} );
Console.WriteLine( $"Result : {result}" );

 

這個範例程式的執行結果參考如下:

1 - 2
3 - 3
6 - 4
10 - 5
Result : 15

Aggregate方法一開始,會先將集合中的前兩個項目取出,將第一個項目「1」代入 「i」;第二個項目「2」代入「j」,接著計算「i+j」得到「3」。

再來將上一步驟得到的「3」代入「i」,將集合中下一個項目「3」代入「j」,接著計算「i+j」得到「6」。

再來將上一步驟得到的「6」代入「i」,將集合中下一個項目「4」代入「j」,接著計算「i+j」得到「10」。

依此類推,再來將上一步驟得到的「10」代入「i」,將集合中下一個項目「5」代入「j」,接著計算「i+j」得到「15」。

而以下範例程式碼則是利用「Aggregate」運算子,將集合中「Customer」物件的「CustomerName」串接成按「,」號區隔的字串:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LINQDemo {
  class Customer {
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string City { get; set; }
    public int PostalCode { get; set; }
    public string Country { get; set; }
  }

  class Program {
    static void Main( string [] args ) {

      List<Customer> customers = new List<Customer> {
        new Customer(){ CustomerID = 1, CustomerName ="Mary" , ContactName = "Maria Anders" , City = "Berlin", PostalCode = 12209 , Country = "Germany" },
        new Customer(){ CustomerID = 2, CustomerName ="Ana" , ContactName = "Ana Trujillo" , City = "México ", PostalCode = 05021 , Country = "Mexico" },
        new Customer(){ CustomerID = 3, CustomerName ="Lili" , ContactName="Futterkiste" , City = "México ", PostalCode = 05023 , Country = "UK" },
        new Customer(){ CustomerID = 4, CustomerName ="Betty" , ContactName="Futterkiste" , City = "México ", PostalCode = 05023 , Country = "US" }
      };
      var result = customers.Aggregate<Customer , string>( "Result : " , ( s , c ) => s += c.CustomerName + ",").TrimEnd(',');
      Console.WriteLine(result);
    }
  }
}

 

這個範例程式的執行結果參考如下:

Result : Mary,Ana,Lili,Betty

範例中「Aggregate」方法的第一個參數是初始值(Seed Value);第二個參數是一個Func委派(Delegate),「s」用來放累計運算完的結果,「c」則是代表資料來源的「Customer」物件。在這個範例中叫用了「TrimEnd」方法來去除最後一個「,」號。你也可以直接叫用「Aggregate<Customer , string , string>()」方法,在第三個參數中處理,例如可將上例程式改寫如下,可以得到相同的執行結果:

var result = customers.Aggregate<Customer , string , string>( "Result : " ,
      ( s , c ) => s += c.CustomerName + "," ,
       s => s.TrimEnd( ',' )
      );
Console.WriteLine( result ); //Result : Mary,Ana,Lili,Betty

提示:C# LINQ查詢運算式目前不支援 「Aggreate」語法。

 

Aggregation 運算子 - Average

「Average」運算子可以將陣列或集合中的數值加總後,計算出平均值,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Average( );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 3

而以下程式碼範例則是計算出集合中「Order」物件「Amount」屬性的平均值:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQDemo {
  class Order {
    public int OrderID { get; set; }
    public int CustomerID { get; set; }
    public int EmployeeID { get; set; }
    public DateTime OrderDate { get; set; }
    public int Amount { get; set; }
    public int ShipperID { get; internal set; }
  }
  class Program {
    static void Main( string [] args ) {

      List<Order> orders = new List<Order> {
        new Order(){ OrderID = 10001 , CustomerID = 2 , EmployeeID = 7 , OrderDate = new DateTime(2018,9,18) , ShipperID = 3 , Amount = 5000},
        new Order(){ OrderID = 10002 , CustomerID = 2 , EmployeeID = 3 , OrderDate = new DateTime(2018,9,19) , ShipperID = 1 , Amount = 4500},
        new Order(){ OrderID = 10003 , CustomerID = 3 , EmployeeID = 8 , OrderDate = new DateTime(2018,9,20) , ShipperID = 2 , Amount =3000}
      };

      var result = orders.Average( o => o.Amount );
      Console.WriteLine( $"Result : {result}" );

    }
  }
}

 

這個範例程式的執行結果參考如下:

Result : 4166.66666666667

提示:C# LINQ查詢運算式目前不支援 「Average」語法。

 

Aggregation 運算子 - Count

「Count」運算子可以計算出陣列或集合中項目的個數,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Count( );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 5

而以下程式碼範例則是計算出集合中「Order」物件「Amount」屬性值大於等於「4000」的項目筆數:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQDemo {
  class Order {
    public int OrderID { get; set; }
    public int CustomerID { get; set; }
    public int EmployeeID { get; set; }
    public DateTime OrderDate { get; set; }
    public int Amount { get; set; }
    public int ShipperID { get; internal set; }
  }
  class Program {
    static void Main( string [] args ) {

      List<Order> orders = new List<Order> {
        new Order(){ OrderID = 10001 , CustomerID = 2 , EmployeeID = 7 , OrderDate = new DateTime(2018,9,18) , ShipperID = 3 , Amount = 5000},
        new Order(){ OrderID = 10002 , CustomerID = 2 , EmployeeID = 3 , OrderDate = new DateTime(2018,9,19) , ShipperID = 1 , Amount = 4500},
        new Order(){ OrderID = 10003 , CustomerID = 3 , EmployeeID = 8 , OrderDate = new DateTime(2018,9,20) , ShipperID = 2 , Amount =3000}
      };

      var result = orders.Count( o => o.Amount >= 4000 );
      Console.WriteLine( $"Result : {result}" );


    }
  }
}

這個範例程式的執行結果參考如下:

Result : 2

提示:C# LINQ查詢運算式目前不支援「Count」語法。

 

Aggregation 運算子 - Max

「Max」運算子用來找出陣列或集合中最大的數值,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Max( );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 5

而以下程式碼範例則是計算出集合中「Order」物件「Amount」屬性包含的最大值:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQDemo {
  class Order {
    public int OrderID { get; set; }
    public int CustomerID { get; set; }
    public int EmployeeID { get; set; }
    public DateTime OrderDate { get; set; }
    public int Amount { get; set; }
    public int ShipperID { get; internal set; }
  }
  class Program {
    static void Main( string [] args ) {

      List<Order> orders = new List<Order> {
        new Order(){ OrderID = 10001 , CustomerID = 2 , EmployeeID = 7 , OrderDate = new DateTime(2018,9,18) , ShipperID = 3 , Amount = 5000},
        new Order(){ OrderID = 10002 , CustomerID = 2 , EmployeeID = 3 , OrderDate = new DateTime(2018,9,19) , ShipperID = 1 , Amount = 4500},
        new Order(){ OrderID = 10003 , CustomerID = 3 , EmployeeID = 8 , OrderDate = new DateTime(2018,9,20) , ShipperID = 2 , Amount = 3000}
      };

      var result = orders.Max( o => o.Amount );
      Console.WriteLine( $"Result : {result}" );

    }
  }
}

 

這個範例程式的執行結果參考如下:

Result : 5000

提示:C# LINQ查詢運算式目前不支援 「Max」語法。

 

Aggregation 運算子 - Sum

「Sum」運算子用來加總陣列或集合中的數值,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Sum( );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 15

若想要加總陣列或集合中大於等於3的數值,參考以下範例程式碼:

 

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Sum( i => {
  if ( i >= 3 ) {
    return i;
  } else {
    return 0;
    }
} );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 12

而以下程式碼範例則是計算出集合中「Order」物件「Amount」屬性值的加總:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINQDemo {
  class Order {
    public int OrderID { get; set; }
    public int CustomerID { get; set; }
    public int EmployeeID { get; set; }
    public DateTime OrderDate { get; set; }
    public int Amount { get; set; }
    public int ShipperID { get; internal set; }
  }
  class Program {
    static void Main( string [] args ) {

      List<Order> orders = new List<Order> {
        new Order(){ OrderID = 10001 , CustomerID = 2 , EmployeeID = 7 , OrderDate = new DateTime(2018,9,18) , ShipperID = 3 , Amount = 5000},
        new Order(){ OrderID = 10002 , CustomerID = 2 , EmployeeID = 3 , OrderDate = new DateTime(2018,9,19) , ShipperID = 1 , Amount = 4500},
        new Order(){ OrderID = 10003 , CustomerID = 3 , EmployeeID = 8 , OrderDate = new DateTime(2018,9,20) , ShipperID = 2 , Amount = 3000}
      };

      var result = orders.Sum( o => o.Amount );
      Console.WriteLine( $"Result : {result}" );


    }
  }
}

 

這個範例程式的執行結果參考如下:

Result : 12500

提示:C# LINQ查詢運算式目前不支援 「Sum」語法。

 

Element運算子 - ElementAt

「ElementAt」運算子回傳陣列或集合中指定索引值(Index)的項目,參考以下範例程式碼,找出索引「3」所在的數值,索引以「0」開始,在以下範例中list索引「0」的項目是「1」;索引「1」的項目是「2」,依此類推:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.ElementAt( 3 );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 4

若指定的索引超過集合中最大項目的索引,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.ElementAt( 8 );
Console.WriteLine( $"Result : {result}" );

則執行將產生例外錯誤,請參考下圖所示:

clip_image002

圖 1:索引超過範圍產生例外錯誤。

提示:C# LINQ查詢運算式目前不支援 「ElementAt」語法。

 

Element運算子 - ElementAtOrDefault

「ElementAtOrDefault」運算子回傳陣列或集合中指定索引值(Index)的項目。「ElementAt 」與「ElementAtOrDefault」的差異是:「ElementAt 」找不到條件相符的資料會產生例外錯誤;而「ElementAtOrDefault」找不到條件相符的資料時不會產生例外錯誤,而是回傳「預設值」,參考以下範例程式碼,找出索引「3」所在的數值:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.ElementAtOrDefault( 3 );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下:

Result : 4

若指定的索引超過集合中最大項目的索引,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.ElementAtOrDefault( 8 );
Console.WriteLine( $"Result : {result}" );

這個範例程式的執行結果參考如下,回傳預設值「0」:

Result : 0

而以下範例從字串集合中找索引「8」的項目,若索引超過陣列或集合中最大項目的索引,「ElementAtOrDefault」方法則回傳字串的預設值「null」:

List<string> list = new List<string>( ) { "1" , "2" , "3" , "4" , "5" };
var result = list.ElementAtOrDefault( 8 );
Console.WriteLine(result == null); // true

提示:C# LINQ查詢運算式目前不支援 「ElementAtOrDefault」語法。

 

Element運算子 – First與FirstOrDefault

「First」與「FirstOrDefault」運算子用來取得陣列或集合中的第一個項目。「First」與「FirstOrDefault」運算子的差異是:「First」方法找不到條件相符的資料會產生例外錯誤;而「FirstOrDefault」方法找不到條件相符的資料時不會產生例外錯誤,而是回傳預設值。參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.First( );
Console.WriteLine( $"Result : {result}" );
var result2 = list.FirstOrDefault( );
Console.WriteLine( $"Result2 : {result2}" );

這個範例程式的執行結果參考如下:

Result : 1
Result2 : 1

以下範例程式碼將大於3的第一個項目回傳

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.First( i => i > 3 );
Console.WriteLine( $"Result : {result}" );
var result2 = list.FirstOrDefault( i => i > 3 );
Console.WriteLine( $"Result2 : {result2}" );

這個範例程式的執行結果參考如下:

Result2 : 4
Result : 4

提示:C# LINQ查詢運算式目前不支援 「First」與「FirstOrDefault」語法。

 

Element運算子 – Last與LastOrDefault

「Last」與「LastOrDefault」運算子用來取得陣列或集合中的最後一個項目。「Last」與「LastOrDefault」運算子的差異是:「Last」方法找不到條件相符的資料會產生例外錯誤;而「LastOrDefault」方法找不到條件相符的資料時不會產生例外錯誤,而是回傳預設值。參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Last( );
Console.WriteLine( $"Result : {result}" );
var result2 = list.FirstOrDefault( );
Console.WriteLine( $"Result2 : {result2}" );

這個範例程式的執行結果參考如下:

Result : 5
Result2 : 5

以下範例程式碼小於3的最後一個項目回傳

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Last( i => i < 3 );
Console.WriteLine( $"Result : {result}" );
var result2 = list. LastOrDefault( i => i < 3 );
Console.WriteLine( $"Result2 : {result2}" );

這個範例程式的執行結果參考如下:

Result2 : 2
Result : 2

提示:C# LINQ查詢運算式目前不支援 「Last」與「LastOrDefault」語法。

Element運算子 – Single與SingleOrDefault

「Single」與「SingleOrDefault」運算子用來取得陣列或集合中唯一的一個項目。「Single」與「SingleOrDefault」運算子的差異是:「Single」方法找不到條件相符的資料會產生例外錯誤;而「SingleOrDefault」方法找不到條件相符的資料時不會產生例外錯誤,而是回傳預設值。參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 };
var result = list.Single( );
Console.WriteLine( $"Result : {result}" );
var result2 = list.SingleOrDefault( );
Console.WriteLine( $"Result2 : {result2}" );

這個範例程式的執行結果參考如下:

Result : 1
Result2 : 1

若來源集合包含兩個項目,則「Single」與「SingleOrDefault」都會產生例外錯誤:

List<int> list = new List<int>( ) { 1 , 2 };
var result = list.Single( ); // Exception
Console.WriteLine( $"Result : {result}" );

var result2 = list.SingleOrDefault( ); // Exception
Console.WriteLine( $"Result2 : {result2}" );

若來源集合沒有任何項目,則「Single」會產生例外錯誤,「SingleOrDefault」會回傳預設值「0」:

List<int> list = new List<int>( ) { };
var result = list.Single( ); // Exception
Console.WriteLine( $"Result : {result}" );

var result2 = list.SingleOrDefault( ); // 預設值 Result2 : 0
Console.WriteLine( $"Result2 : {result2}" );

以下範例程式碼範例將大於「4」的唯一一個項目回傳:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Single( i => i > 4 );
Console.WriteLine( $"Result : {result}" );
var result2 = list.SingleOrDefault( i => i > 4 );
Console.WriteLine( $"Result2 : {result2}" );

這個範例程式的執行結果參考如下:

Result2 :5
Result : 5

若沒有找到相符的唯一一個項目,「Single」方法將產生例外;「SingleOrDefault」則回傳預設值,參考以下範例程式碼:

List<int> list = new List<int>( ) { 1 , 2 , 3 , 4 , 5 };
var result = list.Single( i => i == 6 ); //Exception
Console.WriteLine( $"Result : {result}" );

var result2 = list.SingleOrDefault( i => i == 6 );
Console.WriteLine( $"Result2 : {result2}" ); //Result2 : 0

提示:C# LINQ查詢運算式目前不支援 「Single」與「SingleOrDefault」語法。

Tags:

.NET Magazine國際中文電子雜誌 | C# | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List