c# 兩個(gè)不同類(lèi)海量數(shù)據(jù)集合的合并

背景:有兩個(gè)集合,A集合裝有員工id、name,B集合裝有員工id、sex,員工id相同,分別有百萬(wàn)數(shù)據(jù),怎樣在效率最高的情況將兩個(gè)集合合并成C集合id、name、sex。

一開(kāi)始想到的是兩種最簡(jiǎn)單的思路

  1. 兩次Foreach循環(huán)查詢(xún)匹配。
  2. 使用LINQ查詢(xún)。

第一種兩次foreach循環(huán)次數(shù)為n*n,第二種linq循環(huán)次數(shù)未知,那么就開(kāi)始測(cè)試耗時(shí)了。
數(shù)據(jù)準(zhǔn)備

    class Program
    {
        public static List<Amodel> AList { get; set; } = new List<Amodel>();
        public static List<Bmodel> BList { get; set; } = new List<Bmodel>();

        static void Main(string[] args)
        {
            for (int i = 0; i < 1000*1000 ; i++)
            {
                AList.Add(new Amodel() { id = i, name = Guid.NewGuid().ToString() });
                BList.Add(new Bmodel() { id = i, sex = Guid.NewGuid().ToString() });
            }
            Console.ReadKey();
        }
    }

    public class model
    {
        public int id { get; set; }
        public string name { get; set; }

        public string sex { get; set; }
    }

    public class Amodel
    {
        public int id { get; set; }
        public string name { get; set; }
    }

    public class Bmodel
    {
        public int id { get; set; }
        public string sex { get; set; }
    }

foreach循環(huán)方法

static void ContactListByForeach()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<model> resultList = new List<model>();
            foreach (var itemA in AList)
            {
                foreach (var itemB in BList)
                {
                    if (itemA.id == itemB.id)
                    {
                        var model = new model
                        {
                            id = itemA.id,
                            name = itemA.name,
                            sex = itemB.sex
                        };
                        resultList.Add(model);
                    }
                }
            }
            watch.Stop();
            Console.WriteLine("ContactListByForeach:_____________________" + watch.ElapsedMilliseconds);
        }

linq循環(huán)方法

        static void ContactListByLinq()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            var result = from a in AList
                         join b in BList on a.id equals b.id
                         select new model { id = a.id, name = a.name, sex = b.sex };
            var s = result.ToArray();
            watch.Stop();
            Console.WriteLine("ContactListByLinq:_____________________" + watch.ElapsedMilliseconds);
        }

在測(cè)試中非常尷尬的發(fā)現(xiàn)百萬(wàn)級(jí)數(shù)據(jù)已經(jīng)跑不動(dòng)了,暫時(shí)先改為1萬(wàn)數(shù)據(jù)進(jìn)行測(cè)試,在整理代碼的同時(shí)在foreach循環(huán)方法中又增加了一點(diǎn)優(yōu)化,兩種代碼如下
foreach+lambda循環(huán)

        static void ContactListByForeachAndLambda()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<model> resultList = new List<model>();
            foreach (var itemA in AList)
            {
                var bModel=BList.Where(m=>m.id==itemA.id).FirstOrDefault();
                var model = new model
                {
                    id = itemA.id,
                    name = itemA.name,
                    sex = bModel.sex
                };
                resultList.Add(model);
            }
            watch.Stop();
            Console.WriteLine("ContactListByForeachAndLambda:_____________________" + watch.ElapsedMilliseconds);
        }

純lambda循環(huán)

         static void ContactListByForeachLambda()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<model> resultList = new List<model>();
            resultList = AList.Select(m => new model {
                id = m.id,
                name = m.name,
                sex = BList.Where(n => n.id == m.id).FirstOrDefault().sex
            }).ToList();
            watch.Stop();
            Console.WriteLine("ContactListByForeachLambda:_____________________" + watch.ElapsedMilliseconds);
        }

具體耗時(shí)如下圖:


image.png

可以發(fā)現(xiàn)linq完勝,lambda中的where 效率也是比f(wàn)oreach+if判斷的方式效率略高一點(diǎn)點(diǎn)。
經(jīng)過(guò)大佬指點(diǎn),只回復(fù)了字典二字,寫(xiě)出如下代碼
dic

        static void ContactListByListAndDic()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            var newBlist = BList.ToDictionary(key => key.id);
            List<model> tempStack = new List<model>();
            for (int i = 0; i < AList.Count; i++)
            {
                var key = AList[i].id;
                tempStack.Add(new model
                {
                    id = key,
                    name = AList[i].name,
                    sex = newBlist.ContainsKey(key) ? newBlist[key].sex : string.Empty
                });
            }
            var s = tempStack.ToArray();
            watch.Stop();
            Console.WriteLine("ContactListByListAndDic:_____________________" + watch.ElapsedMilliseconds);
        }

這時(shí)將數(shù)據(jù)量恢復(fù)到百萬(wàn)級(jí)別 得到如下結(jié)果


image.png

原因是字典中每一個(gè)元素都是鍵值對(duì),字典的key就相當(dāng)于數(shù)據(jù)庫(kù)中的索引。
你知道Dictionary查找速度為什么快嗎
這篇文章講的很詳細(xì),我就不羅嗦了。

在和朋友探討時(shí),朋友又給出了一個(gè)優(yōu)化,就是將ContactListByListAndDic方法中的list更改為stack。
結(jié)果如下:數(shù)據(jù)偶爾有波動(dòng),大部分情況下stack獲勝。


image.png

其中查看list.Add源碼


image.png

其中這個(gè)方法是一個(gè)自動(dòng)擴(kuò)容的過(guò)程
image.png

而stack中沒(méi)有這一步


image.png

難道是每次的擴(kuò)容導(dǎo)致的?不過(guò)在指定了list的長(zhǎng)度之后發(fā)現(xiàn)還是stack快一點(diǎn),這一點(diǎn)沒(méi)有搞明白,希望大牛指點(diǎn)一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,328評(píng)論 2 89
  • 應(yīng)用程序還需要操作存儲(chǔ)在其他數(shù)據(jù)源(如SQL數(shù)據(jù)庫(kù)或XML文件)中的數(shù)據(jù),甚至通過(guò)Web服務(wù)訪(fǎng)問(wèn)它們。傳統(tǒng)上,查詢(xún)...
    CarlDonitz閱讀 689評(píng)論 0 0
  • Streams 的背景,以及 Java 8 中的使用詳解 為什么需要 Stream Stream 作為 Java ...
    Java黎先生閱讀 869評(píng)論 0 8
  • 為什么你明明寫(xiě)了一堆干貨,而且還是一旦應(yīng)用就能得到讓股票漲30%的干貨、讓屌絲馬上要到女生微信號(hào)的干貨、讓健...
    牙麻呂閱讀 980評(píng)論 0 0
  • 前幾天就開(kāi)始和禎禎可可說(shuō)媽媽馬上又要出門(mén)學(xué)習(xí)了,你們到時(shí)候在家里要乖乖的,今天早晨醒來(lái),看著她們還在睡夢(mèng)中,我馬上...
    LittleWendy閱讀 334評(píng)論 0 3

友情鏈接更多精彩內(nèi)容