欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C#.net core 基礎(chǔ) - 擴(kuò)展數(shù)組添加刪除性能最好的方法

freeflydom
2025年1月6日 10:7 本文熱度 145

今天在編碼的時(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)如下:

public static int[] AddByList(int[] source, int[] added)
{
    var list = source.ToList();
    list.AddRange(added);
    return list.ToArray();
}

2、通過IEnumerable方法實(shí)現(xiàn)

因?yàn)閿?shù)組實(shí)現(xiàn)了IEnumerable接口,所以可以直接調(diào)用Concat方法實(shí)現(xiàn)兩個(gè)數(shù)組拼接。代碼實(shí)現(xiàn)如下:

public static int[] AddByConcat(int[] source, int[] added)
{
    return source.Concat(added).ToArray();
}

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)如下:

public static int[] AddByCopy(int[] source, int[] added)
 {
     var size = source.Length + added.Length;
     var array = new int[size];
     // 復(fù)制原數(shù)組  
     Array.Copy(source, array, source.Length);
     // 添加新元素  
     Array.Copy(added, 0, array, source.Length, added.Length);
     return array;
 }

4、通過Span方法實(shí)現(xiàn)

Span也有一個(gè)類似Array的Copy方法,功能也類似,就是CopyTo方法。代碼實(shí)現(xiàn)如下:

public static int[] AddBySpan(int[] source, int[] added)
{
    Span<int> sourceSpan = source;
    Span<int> addedSpan = added;
    Span<int> span = new int[source.Length + added.Length];
    // 復(fù)制原數(shù)組
    sourceSpan.CopyTo(span);
    // 添加新元素
    addedSpan.CopyTo(span.Slice(sourceSpan.Length)); 
    return span.ToArray();
}

我想到了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)如下:

public static int[] RemoveByList(int[] source, int[] added)
{
    var list = source.ToList();
    list.RemoveAll(x => added.Contains(x));
    return list.ToArray();
}

2、通過IEnumerable方法實(shí)現(xiàn)

因?yàn)閿?shù)組實(shí)現(xiàn)了IEnumerable接口,所以可以直接調(diào)用Where方法進(jìn)行過濾。代碼實(shí)現(xiàn)如下:

public static int[] RemoveByWhere(int[] source, int[] added)
{
     return source.Where(x => !added.Contains(x)).ToArray();
}

3、通過Array方法實(shí)現(xiàn)

Array有個(gè)FindAll靜態(tài)方法可以實(shí)現(xiàn)根據(jù)條件查找數(shù)組。代碼實(shí)現(xiàn)如下:

public static int[] RemoveByArray(int[] source, int[] added)
{
    return Array.FindAll(source, x => !added.Contains(x));
}

4、通過For+List方式實(shí)現(xiàn)

直接遍歷原數(shù)組,把滿足條件的元素放入List中,然后轉(zhuǎn)為數(shù)組返回。代碼實(shí)現(xiàn)如下:

public static int[] RemoveByForList(int[] source, int[] added)
{
    var list = new List<int>();
    foreach (int item in source)
    {
        if (!added.Contains(item))
        {
            list.Add(item);
        }
    }
    return list.ToArray();
}

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)如下:

public static int[] RemoveByForMarkCopy(int[] source, int[] added)
{
    var idx = 0;
    foreach (var item in source)
    {
        if (!added.Contains(item))
        {
            // 標(biāo)記有效元素
            source[idx++] = item; 
        }
    }
    // 創(chuàng)建新數(shù)組并復(fù)制有效元素
    var array = new int[idx];
    Array.Copy(source, array, idx);
    return array;
}

6、通過For+標(biāo)記+Resize方式實(shí)現(xiàn)

這個(gè)方法和上一個(gè)方法實(shí)現(xiàn)基本一致,主要差別在最后一步,這個(gè)方法是直接通過Array的Resize靜態(tài)方法把原數(shù)組調(diào)整為我們要的并返回。代碼實(shí)現(xiàn)如下:

public static int[] RemoveByForMarkResize(int[] source, int[] added)
{
    var idx = 0;
    foreach (var item in source)
    {
        if (!added.Contains(item))
        {
            //標(biāo)記有效元素
            source[idx++] = item; 
        }
    }
    //調(diào)整數(shù)組大小
    Array.Resize(ref source, idx); 
    return source;
}

同樣的我們?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)潔。形如下面兩種形式,你更喜歡那種?

//擴(kuò)展方法
var result = source.Add(added);
//靜態(tài)幫助類方法
var result = ArrayHelper.Add(source, added);

現(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),可以按需使用吧。

public static class ArrayExtensions
{
    public static T[] AddRange<T>(this T[] source, T[] added)
    {
        var size = source.Length + added.Length;
        var array = new T[size];
        Array.Copy(source, array, source.Length);
        Array.Copy(added, 0, array, source.Length, added.Length);
        return array;
    }
    public static T[] RemoveAll<T>(this T[] source, Predicate<T> match)
    {
        return Array.FindAll(source, a => !match(a));
    }
}
public static class ArrayHelper
{
    public static void AddRange<T>(ref T[] source, T[] added)
    {
        var size = source.Length + added.Length;
        var array = new T[size];
        Array.Copy(source, array, source.Length);
        Array.Copy(added, 0, array, source.Length, added.Length);
        source = array;
    }
    public static void RemoveAll<T>(ref T[] source, Predicate<T> match)
    {
        source = Array.FindAll(source, a => !match(a));
    }
}

:測(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)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved