c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)
轉載地址:http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html
剛看了篇文章 《Linq的Distinct太不給力了》,文中給出了一個解決辦法,略顯復雜。
試想如果能寫成下面的樣子,是不是更簡單優雅:
| 1 2 | var p1 = products.Distinct(p => p.ID); var p2 = products.Distinct(p => p.Name); |
使用一個簡單的 lambda 作為參數,也符合 Linq 一貫的風格。
可通過擴展方法實現:
Distinct 擴展方法
首先,創建一個通用比較的類,實現 IEqualityComparer<T> 接口:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq;public class CommonEqualityComparer<T, V> : IEqualityComparer<T> {private Func<T, V> keySelector;public CommonEqualityComparer(Func<T, V> keySelector){this.keySelector = keySelector;}public bool Equals(T x, T y){return EqualityComparer<V>.Default.Equals(keySelector(x), keySelector(y));}public int GetHashCode(T obj){return EqualityComparer<V>.Default.GetHashCode(keySelector(obj));} } |
第 17 行,用到了?EqualityComparer<T> 類,本文最后有簡要說明。
借助上面這個類,Distinct?擴展方法就很好寫了:
| 1 2 3 4 5 6 7 | public static class DistinctExtensions {public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector){return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));} } |
呵呵,簡單吧!
Distinct 使用示例
根據 ID :
| 1 2 3 4 5 6 7 | var data1 = new Person[] {new Person{ ID = 1, Name = "鶴沖天"},new Person{ ID = 1, Name = "ldp"} }; var ps1 = data1.Distinct(p => p.ID).ToArray(); |
根據 Name:
| 1 2 3 4 5 7 | var data2 = new Person[] {new Person{ ID = 1, Name = "鶴沖天"},new Person{ ID = 2, Name = "鶴沖天"} }; var ps2 = data2.Distinct(p => p.Name).ToArray(); |
看了回復后,我做了些改進,推薦使用下面的方式:
改進
回復中有朋友提到“不區分大小寫地排除重復的字符串”,也不難實現,只需要把上面的代碼改進下就 OK:
CommonEqualityComparer<T, V> 類:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq;public class CommonEqualityComparer<T, V> : IEqualityComparer<T> {private Func<T, V> keySelector;private IEqualityComparer<V> comparer;public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer){this.keySelector = keySelector;this.comparer = comparer;}public CommonEqualityComparer(Func<T, V> keySelector): this(keySelector, EqualityComparer<V>.Default){ }public bool Equals(T x, T y){return comparer.Equals(keySelector(x), keySelector(y));}public int GetHashCode(T obj){return comparer.GetHashCode(keySelector(obj));} } |
Distinct?擴展方法:
| 1 2 3 4 5 6 7 8 9 10 11 12 | public static class DistinctExtensions {public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector){return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));}public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer){return source.Distinct(new CommonEqualityComparer<T, V>(keySelector, comparer));} } |
借助可選參數,這兩個擴展方法也可以合成一個:
| 1 2 3 4 5 | public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer = EqualityComparer<V>.Default) {return source.Distinct(new CommonEqualityComparer<T, V>(keySelector, comparer)); } |
(同樣,CommonEqualityComparer<T, V>類的兩個構造函數也可以合二為一)
使用示例:
| 1 2 3 4 5 6 7 | var data3 = new Person[] {new Person{ ID = 1, Name = "LDP"},new Person{ ID = 2, Name = "ldp"} }; var ps3 = data3.Distinct(p => p.Name, StringComparer.CurrentCultureIgnoreCase).ToArray(); |
EqualityComparer<T> 類 簡要說明
EqualityComparer<T>為?IEqualityComparer<T>?泛型接口的實現提供基類,它在 .net 4 中有五個重要的子類,見下圖:
這五個子類分別用不同類型數據的相等性比較,從類名我們可以略知一二。
這五個子類都是內部類(internal),不能直接訪問,EqualityComparer<T> 類提供一個簡單的屬性 Default。EqualityComparer<T> 會根據傳入的 T 的類型,加載不同的子類,并會予以緩存提高性能。
| 基礎篇: | 中文處理、string 常用擴展、byte 常用擴展、Random 擴展、Dictionary<TKey, TValue> 擴展、WhereIf 擴展、IsBetween 通用擴展、WhereIf 擴展、Distinct 擴展 |
| 高級篇: | 改進 Scottgu 的 "In" 擴展、Aggregate擴展其改進、Enumerable.Cast<T>應用、對擴展進行分組管理、ToString(string format) 擴展、WinForm 控件選擇器、樹”通用遍歷器、Type類擴展 |
| 變態篇: | 由Fibonacci數列引出“委托擴展”及“遞推遞歸委托”、封裝 if/else、swith/case及while、switch/case 組擴展、string 的翻身革命 |
| 性能篇: | 擴展方法性能初測 |
| MVC篇: | 巧用擴展方法優先級,美化所有頁面TextBoxFor文本框 |
-------------------
轉載于:https://www.cnblogs.com/yxlblogs/p/3737164.html
總結
以上是生活随笔為你收集整理的c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】shell学习笔记(一)——学习目
- 下一篇: CryptoAPI 学习