2023年4月6日 星期四

透過 LINQ 達到自訂型別比對的效果

使用 LINQ 有時會需要比對相關集合,若集合內比對的元素為「字串」或是「數值」那就單純許多,但

若是欲比對的元素為自訂型別(Class),那就需要注意了;這邊稍微紀錄一下若自訂型別屬性不多時,可

使用較為簡潔的比對方式...



關於自訂型別的比對,黑大之前有討論過一篇,可自行複習,其實使用相關函式都需要注意,

如Intersect()、Exists()及Contains()


先撰寫複習的版本


定義 Person Class,再設計兩個集合並且取出交集(Intersect)的項目



跑執行,印出 no element,如預期,因為 Reference Type 需要需要覆寫 Equals() 及GetHashCode(),

這部分後面會稍微帶到


此時,若將 Person 的型別調整為 struct ,則會印出 t1 與 t2 相關屬性


若保持 Person 為 class 型別,則需要覆寫 Equals() 及GetHashCode(),這樣比對就會符合我們要的結果




另外種實現方式,若不想覆寫相關函式,也不能將 Person class 改為 struct ,可參考以下技巧達到效果

模擬 Intersect


先將 Person 的 Equals()及GetHashCode() 註解起來



再撰寫 LINQ 取得 Persons,將兩個集合整合起來,再透過 GroupBy 的特性來比對哪些是

重複的項目,然而由於 Group 會將集合轉為 IGrouping 型式,最後透過 Select 轉為 IEnumable,

這樣後面的 foreach 內容就不用調整



印出的結果是一樣的



若是更加簡便的方式使用 Enumerable.Intersect() 方法,並且指定比對欄位,如下所示




其中這方法其實也適用單一集合中,找出重複的項目,以下簡單示範

設計集合,其中有兩組項目重複 t99、t5


同樣的透過 GroupBy() 找出相關項目,並且列出



以上是實作交集(Intersect) 的效果, 若要達到差集(Except)的效果,其實僅需要將 g.Count() > 1

改為 g.Count() == 1 即可



再來測試實作如何達到 Distinct()、Union()的效果

首先 Union()為 合併兩個集合但是排除重複的,以左邊為優先列舉出來,但因為自訂型別的情境,

故該函式若沒有刻意複寫 Equals()及GetHashCode() 的前提下,是不會達到預計效果的,如下


同樣兩個集合 persons1、persons2



接著我們 Union() 兩個集合,預計應該會 t1、t2、t3 各一筆(排除重複的),但結果不然


調整實作後,即可得到預期效果


若是更加簡便的方式使用 Enumerable.Union() 方法,並且指定比對欄位,如下所示



Distinct() 的操作如下,大夥參考參考


或是如下做法



若要達到 SequenceEqual() 的效果,也可以如下呈現,須注意該函式是按照順序逐項比對


最後結論,若自訂型別的屬性數量較少,應該會以選用這個方式實作


沒有留言:

張貼留言