C#黔驴技巧之去重(Distinct)
關于C#中默認的Distinct方法在什么情況下才能去重,這個就不用我再多講,針對集合對象去重默認實現(xiàn)將不再滿足,于是乎我們需要自定義實現(xiàn)來解決這個問題,接下來我們詳細講解幾種常見去重方案,孰好孰歹自行判之。
分組
首先給出我們需要用到的對象,如下:
接下來我們添加100萬條數(shù)據(jù)到集合中,如下:
接下來我們對年齡和名稱進行分組,然后取第一條即可達到去重,如下:
list?=?list.GroupBy(d?=>?new?{?d.Age,?d.Name?}).Select(d?=>?d.FirstOrDefault()).ToList();HashSet
我們知道在C#中HashSet對于重復元素會進行過濾篩選,所以我們寫下如下擴展方法,遍歷集合元素,最后利用HashSet進行過濾達到去重目的,如下:
public?static?IEnumerable<TSource>?Distinct<TSource,?TKey>(this?IEnumerable<TSource>?source,Func<TSource,?TKey>?keySelector){var?hashSet?=?new?HashSet<TKey>();foreach?(TSource?element?in?source){if?(hashSet.Add(keySelector(element))){yield?return?element;}}}最后調(diào)用上述擴展方法即可去重,如下:
?list?=?list.Distinct(d?=>?new?{?d.Age,?d.Name?}).ToList();IEqualityComparer
在實際項目中有很多通過具體實現(xiàn)類實現(xiàn)該接口,通過重寫Equals和HashCode比較屬性值來達到去重目的,因為對于每一個類都得實現(xiàn)對應比較器,所以并不通用,反而利用上述方式才是最佳,其實我們大可借助該比較接口實現(xiàn)通用解決方案,對于每一個類都得實現(xiàn)一個比較器的原因在于,我們將屬性比較放在類該接口內(nèi)部,如果我們將屬性比較放在外圍呢,這個時候就達到了通用解決方案,那么我們怎么實現(xiàn)呢,通過委托來實現(xiàn),實現(xiàn)該接口的本質(zhì)無非就是比較HashCode,然后通過Equals比較其值,當比較HashCode時,我們強制其值為一個常量(比如0),當重寫Equals方法我們調(diào)用委托即可,如下:
public?static?class?Extensions {public?static?IEnumerable<T>?Distinct<T>(this?IEnumerable<T>?source,?Func<T,?T,?bool>?comparer)where?T?:?class=>?source.Distinct(new?DynamicEqualityComparer<T>(comparer));private?sealed?class?DynamicEqualityComparer<T>?:?IEqualityComparer<T>where?T?:?class{private?readonly?Func<T,?T,?bool>?_func;public?DynamicEqualityComparer(Func<T,?T,?bool>?func){_func?=?func;}public?bool?Equals(T?x,?T?y)?=>?_func(x,?y);public?int?GetHashCode(T?obj)?=>?0;} }最終通過指定屬性進行比較即可去重,如下:
list?=?list.Distinct((a,?b)?=>?a.Age?==?b.Age?&&?a.Name?==?b.Name).ToList();性能比較
以上3種常見方式我們已經(jīng)介紹完畢了,當數(shù)據(jù)量比較小時,我們大可忽略對集合進行各種操作所帶來的性能,但是一旦數(shù)據(jù)量很大時,我們可能需要考慮性能,能節(jié)省一點時間或許有必要,于是乎,在上述100萬條數(shù)據(jù)前提下,我們來分析其耗時情況,如下:
var?list?=?new?List<Person>(); for?(int?i?=?0;?i?<?1000000;?i++) {list.Add(new?Person()?{?Age?=?18,?Name?=?"jeffcky"?}); }var?time1?=?Time(()?=> {list.GroupBy(d?=>?new?{?d.Age,?d.Name?}).Select(d?=>?d.FirstOrDefault()).ToList(); }); Console.WriteLine($"分組耗時:{time1}");var?time2?=?Time(()?=> {list.Distinct(d?=>?new?{?d.Age,?d.Name?}).ToList(); }); Console.WriteLine($"HashSet耗時:{time2}");var?time3?=?Time(()?=> {list.Distinct((a,?b)?=>?a.Age?==?b.Age?&&?a.Name?==?b.Name).ToList(); }); Console.WriteLine($"委托耗時:{time3}");static?long?Time(Action?action) {var?stopwatch?=?new?Stopwatch();stopwatch.Start();action();stopwatch.Stop();return?stopwatch.ElapsedMilliseconds; }結果:第一種方案耗時(252ms),第二種方案耗時(147ms),第三種方案耗時(63ms)
上述結果耗時大小比較理論應該不會出現(xiàn)逆轉的情況,只是多少的問題,數(shù)據(jù)量較少時理論上差異也很明顯,本文對于去重方式只是基于性能角度來分析,還是那句話大部分情況下,我們完全不需要考慮這些問題,不過,作為程序員的我們可能也想寫出高性能、高質(zhì)量的代碼吧,有時候多考慮考慮也無妨,對自身有個好的代碼質(zhì)量要求也未嘗不可,也還是那句話,孰好孰歹,自行判之。?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的C#黔驴技巧之去重(Distinct)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我整理了100G的.Net学习资料,速来
- 下一篇: c#: 协变和逆变深度解析