C#.net core 基礎(chǔ) - 擴(kuò)展數(shù)組添加刪除性能最好的方法
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
今天在編碼的時(shí)候遇到了一個(gè)問題,需要對(duì)數(shù)組變量添加新元素和刪除元素,因?yàn)閿?shù)組是固定大小的,因此對(duì)新增和刪除并不友好,但有時(shí)候又會(huì)用到,因此想針對(duì)數(shù)組封裝兩個(gè)擴(kuò)展方法:新增元素與刪除元素,并能到達(dá)以下三個(gè)目標(biāo): 1、性能優(yōu)異; 2、兼容性好; 3、方便使用; 這三個(gè)目標(biāo)最麻煩的應(yīng)該就是性能優(yōu)異了,比較后面兩個(gè)可以通過泛型方法,擴(kuò)展方法,按引用傳遞等語法實(shí)現(xiàn),性能優(yōu)異卻要在十來種實(shí)現(xiàn)方法中選出兩個(gè)最優(yōu)的實(shí)現(xiàn)。那關(guān)于數(shù)組新增和刪除元素你能想到多少種實(shí)現(xiàn)呢?下面我們來一起看看那個(gè)性能最好。 01、新增元素實(shí)現(xiàn)方法對(duì)比1、通過List方法實(shí)現(xiàn)通過轉(zhuǎn)為L(zhǎng)ist,再用AddRange方法添加元素,最后再轉(zhuǎn)為數(shù)組返回。代碼實(shí)現(xiàn)如下:
2、通過IEnumerable方法實(shí)現(xiàn)因?yàn)閿?shù)組實(shí)現(xiàn)了IEnumerable接口,所以可以直接調(diào)用Concat方法實(shí)現(xiàn)兩個(gè)數(shù)組拼接。代碼實(shí)現(xiàn)如下:
3、通過Array方法實(shí)現(xiàn)Array有個(gè)Copy靜態(tài)方法可以實(shí)現(xiàn)把數(shù)組復(fù)制到目標(biāo)數(shù)組中,因此我們可以先構(gòu)建一個(gè)大數(shù)組,然后用Copy方法把兩個(gè)數(shù)組都復(fù)制到大數(shù)組中。代碼實(shí)現(xiàn)如下:
4、通過Span方法實(shí)現(xiàn)Span也有一個(gè)類似Array的Copy方法,功能也類似,就是CopyTo方法。代碼實(shí)現(xiàn)如下:
我想到了4種方法來實(shí)現(xiàn),如果你有不同的方法希望可以給我留言,不吝賜教。那么那種方法效率最高呢?按我理解作為現(xiàn)在.net core性能中的一等公民Span應(yīng)該性能是最好的。 我們也不瞎猜了,直接來一組基準(zhǔn)測(cè)試對(duì)比。我們對(duì)4個(gè)方法,分三組測(cè)試,每組分別隨機(jī)生成兩個(gè)100、1000、10000個(gè)元素的數(shù)組,然后每組再進(jìn)行10000次測(cè)試。 測(cè)試結(jié)果如下: 整體排名:AddByCopy > AddByConcat > AddBySpan > AddByList。 可以發(fā)現(xiàn)性能最好的竟然是Array的Copy方法,不但速度最優(yōu),而且內(nèi)存使用方面也是最優(yōu)的。 而我認(rèn)為性能最好的Span整體表現(xiàn)還不如IEnumerable的Concat方法。 最終Array的Copy方法完勝。 02、刪除元素實(shí)現(xiàn)方法對(duì)比1、通過List方法實(shí)現(xiàn)還是先把數(shù)組轉(zhuǎn)為L(zhǎng)ist,然后再用RemoveAll進(jìn)行刪除,最后把結(jié)果轉(zhuǎn)為數(shù)組返回。代碼實(shí)現(xiàn)如下:
2、通過IEnumerable方法實(shí)現(xiàn)因?yàn)閿?shù)組實(shí)現(xiàn)了IEnumerable接口,所以可以直接調(diào)用Where方法進(jìn)行過濾。代碼實(shí)現(xiàn)如下:
3、通過Array方法實(shí)現(xiàn)Array有個(gè)FindAll靜態(tài)方法可以實(shí)現(xiàn)根據(jù)條件查找數(shù)組。代碼實(shí)現(xiàn)如下:
4、通過For+List方式實(shí)現(xiàn)直接遍歷原數(shù)組,把滿足條件的元素放入List中,然后轉(zhuǎn)為數(shù)組返回。代碼實(shí)現(xiàn)如下:
5、通過For+標(biāo)記+Copy方式實(shí)現(xiàn)還是直接遍歷原數(shù)組,但是我們不創(chuàng)建新集合,直接把滿足的元素放在原數(shù)組中,因?yàn)閺脑瓟?shù)組第一個(gè)元素迭代,如果元素滿足則放入第一個(gè)元素其索引自動(dòng)加1,如果不滿足則等下一個(gè)滿足的元素放入其索引保持不變,以此類推,直至所有元素處理完成,最后再把原數(shù)組中滿足要求的數(shù)組復(fù)制到新數(shù)據(jù)中返回。代碼實(shí)現(xiàn)如下:
6、通過For+標(biāo)記+Resize方式實(shí)現(xiàn)這個(gè)方法和上一個(gè)方法實(shí)現(xiàn)基本一致,主要差別在最后一步,這個(gè)方法是直接通過Array的Resize靜態(tài)方法把原數(shù)組調(diào)整為我們要的并返回。代碼實(shí)現(xiàn)如下:
同樣的我們?cè)僮鲆唤M基準(zhǔn)測(cè)試對(duì)比,結(jié)果如下: 可以發(fā)現(xiàn)最后兩個(gè)方法隨著數(shù)組元素增加性能越來越差,而其他四種方法相差不大。既然如此我們就選擇Array原生方法FindAll。 03、實(shí)現(xiàn)封裝方法新增刪除的兩個(gè)方法已經(jīng)確定,我們第一個(gè)目標(biāo)就解決了。 既然要封裝為公共的方法,那么就必要要有良好的兼容性,我們示例雖然都是用的int類型數(shù)組,但是實(shí)際使用中不知道會(huì)碰到什么類型,因此最好方式是選擇泛型方法。這樣第二個(gè)目標(biāo)就解決了。 那么第三個(gè)目標(biāo)方便使用要怎么辦呢?第一想法既然做成公共方法了,直接做一個(gè)幫助類,比如ArrayHelper,然后把兩個(gè)實(shí)現(xiàn)方法直接以靜態(tài)方法放進(jìn)去。 但是我更偏向使用擴(kuò)展方法,原因有二,其一可以利用編輯器直接智能提示出該方法,其二代碼更簡(jiǎn)潔。形如下面兩種形式,你更喜歡那種?
現(xiàn)在還有一個(gè)問題,這個(gè)方法是以返回值的方式返回最后的結(jié)果呢?還是直接修改原數(shù)組呢??jī)煞N方式各有優(yōu)點(diǎn),返回新數(shù)組,則原數(shù)組不變便于鏈?zhǔn)秸{(diào)用也避免一些副作用,直接修改原數(shù)組內(nèi)存效率高。 我們的兩個(gè)方法是新增元素和刪除元素,其語義更貼合對(duì)原始數(shù)據(jù)進(jìn)行操作其結(jié)果也作用在自身。因此我更傾向無返回值的方式。 那現(xiàn)在有個(gè)尷尬的問題,不知道你還記得我們上一章節(jié)《C#|.net core 基礎(chǔ) - 值傳遞 vs 引用傳遞》講的值傳遞和引用傳遞,這里就有個(gè)這樣的問題,如果我們現(xiàn)在想用擴(kuò)展方法并且無返回值直接修改原數(shù)組,那么需要對(duì)擴(kuò)展方法第一個(gè)參數(shù)使用ref修飾符,但是擴(kuò)展方法對(duì)此有限制要求【第一個(gè)參數(shù)必須是struct 或是被約束為結(jié)構(gòu)的泛型類型】,顯示泛型數(shù)組不滿足這個(gè)限制。因此無法做到我心目中最理想的封裝方式了,下面看看擴(kuò)展方法和幫助類的代碼實(shí)現(xiàn),可以按需使用吧。
注:測(cè)試方法代碼以及示例源碼都已經(jīng)上傳至代碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Planner ?轉(zhuǎn)自https://www.cnblogs.com/hugogoos/p/18421745 該文章在 2025/1/6 10:07:20 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |