C# 3.0 集合運算 (交集、差集、聯集、互斥) - Rference Type

C# 3.0 集合運算 (交集、差集、聯集、互斥) - Rference Type

前篇【C# 3.0 集合運算 (交集、差集、聯集、互斥) - Value Type】介紹實值型別的集合運算,本篇介紹參考型別 (reference type) 的集合運算。首先,繼續拿我常用的 Product 類別,首先建立兩個 List<Product> 集合,當作練習之用。

範例碼,如下:

   1:  var pList1 = new List<Product>
   2:              {
   3:                      new Product {ID = 1, Name = "A", Price = 7, ShipDate = new DateTime(2006, 1, 19)}, 
   4:                      new Product {ID = 2, Name = "B", Price = 237, ShipDate = new DateTime(2006, 10, 17)}, 
   5:                      new Product {ID = 3, Name = "C", Price = 17, ShipDate = new DateTime(2007, 2, 12)}, 
   6:                      new Product {ID = 4, Name = "D", Price = 57, ShipDate = new DateTime(2005, 9, 11)}
   7:              };
   8:   
   9:  var pList2 = new List<Product>
  10:              {
  11:                      new Product {ID = 1, Name = "A", Price = 7, ShipDate = new DateTime(2006, 1, 19)}, 
  12:                      new Product {ID = 5, Name = "E", Price = 88, ShipDate = new DateTime(2008, 12, 10)}, 
  13:                      new Product {ID = 6, Name = "F", Price = 99, ShipDate = new DateTime(2008, 6, 4)}, 
  14:                      new Product {ID = 4, Name = "D", Price = 57, ShipDate = new DateTime(2005, 9, 11)}
  15:              };
  16:   
  17:  // pList1 聯集 pList2
  18:  foreach (var product in pList1.Union(pList2))
  19:  {
  20:      Console.WriteLine(product.ToString());
  21:  }

 

 

輸出的結果為:

   1:  ID: 1, Name: A, Price: 7, ShipDate: 2006/1/19
   2:  ID: 2, Name: B, Price: 237, ShipDate: 2006/10/17
   3:  ID: 3, Name: C, Price: 17, ShipDate: 2007/2/12
   4:  ID: 4, Name: D, Price: 57, ShipDate: 2005/9/11
   5:  ID: 1, Name: A, Price: 7, ShipDate: 2006/1/19
   6:  ID: 5, Name: E, Price: 88, ShipDate: 2008/12/10
   7:  ID: 6, Name: F, Price: 99, ShipDate: 2008/6/4
   8:  ID: 4, Name: D, Price: 57, ShipDate: 2005/9/11

 

 

這結果似乎有點不太對勁,沒有如我們所預期合併為 Product ID { 1 2 3 4 5 6 } 的集合,而是列出 Product ID { 1 2 3 4 1 5 6 4 } 的組合。這是因為我們缺少了一個動作就是覆寫自訂類別的 Equals() 方法GetHashCode()方法,使得無法讓編譯器知道什麼是相同的物件。所以我們下一步就是在自定類別 Product 中撰寫 Equals() 方法GetHashCode()方法

範例碼,如下:

   1:  public class Product
   2:  {
   3:      public int ID { get; set; }
   4:      public string Name { get; set; }
   5:      public double Price { get; set; }
   6:      public DateTime ShipDate { get; set; }
   7:   
   8:      public override string ToString()
   9:      {
  10:          return string.Format("ID: {0}, Name: {1}, Price: {2}, ShipDate: {3}", ID, Name, Price, ShipDate.ToShortDateString());
  11:      }
  12:   
  13:      public override bool Equals(object obj)
  14:      {
  15:          if(obj is Product)
  16:          {
  17:              Product p = (Product) obj;
  18:              return (p.ID == ID && p.Name == Name && p.Price == Price && p.ShipDate == ShipDate);
  19:          }
  20:          return false;
  21:      }
  22:   
  23:      public override int GetHashCode()
  24:      {
  25:          return ToString().GetHashCode();
  26:      }
  27:  }

 

 

此時,我們再一次執行剛剛的程式碼,結果就會變成以下的結果:

   1:  // pList1 聯集 pList2
   2:  foreach (var product in pList1.Union(pList2))
   3:  {
   4:      Console.WriteLine(product.ToString());
   5:  }
   6:   
   7:  // pList1 聯集 pList2 輸出結果
   8:  ID: 1, Name: A, Price: 7, ShipDate: 2006/1/19
   9:  ID: 2, Name: B, Price: 237, ShipDate: 2006/10/17
  10:  ID: 3, Name: C, Price: 17, ShipDate: 2007/2/12
  11:  ID: 4, Name: D, Price: 57, ShipDate: 2005/9/11
  12:  ID: 5, Name: E, Price: 88, ShipDate: 2008/12/10
  13:  ID: 6, Name: F, Price: 99, ShipDate: 2008/6/4

 

 

撰寫了 Equals() 方法GetHashCode()方法後,剩下來的交集、差集、互斥等集合運算就跟實值型別 (value type) 的使用方式,沒有啥兩樣囉,範例碼如下:

   1:  // pList1 交集 pList2
   2:  foreach (var product in pList1.Intersect(pList2))
   3:  {
   4:      Console.WriteLine(product.ToString());
   5:  }
   6:   
   7:  // pList1 交集 pList2 輸出結果
   8:  // ID: 1, Name: A, Price: 7, ShipDate: 2006/1/19
   9:  // ID: 4, Name: D, Price: 57, ShipDate: 2005/9/11
  10:   
  11:  // pList1 差集 pList2
  12:  foreach (var product in pList1.Except(pList2))
  13:  {
  14:      Console.WriteLine(product.ToString());
  15:  }
  16:   
  17:  // pList1 差集 pList2 輸出結果
  18:  // ID: 2, Name: B, Price: 237, ShipDate: 2006/10/17
  19:  // ID: 3, Name: C, Price: 17, ShipDate: 2007/2/12
  20:   
  21:  // pList1 互斥 pList2
  22:  foreach (var product in pList1.Except(pList2).Union(pList2.Except(pList1)))
  23:  {
  24:      Console.WriteLine(product.ToString());
  25:  }
  26:   
  27:  // pList1 互斥 pList2 輸出結果
  28:  // ID: 2, Name: B, Price: 237, ShipDate: 2006/10/17
  29:  // ID: 3, Name: C, Price: 17, ShipDate: 2007/2/12
  30:  // ID: 5, Name: E, Price: 88, ShipDate: 2008/12/10
  31:  // ID: 6, Name: F, Price: 99, ShipDate: 2008/6/4