【4858.com】List和Dictionary泛型类查找功能浅析,你能熟习使用Dictionary字典和List列表吗

By admin in 4858.com on 2019年5月5日

【4858.com】List和Dictionary泛型类查找功能浅析,你能熟习使用Dictionary字典和List列表吗。 

  命名空间System.Collections.Generic中有三个特别主要,而且常用的泛型集结类,它们各自是Dictionary<TKey,TValue>字典和List<T>列表。Dictionary字典经常用于保存键/值对的数目,而List列表通中用于保存可因而索引访问的靶子的强类型列表。下边来总括一下,用代码来演示怎么伊始化,增添,修改,删除和遍历成分。

      
 List和Dictionary泛型类查找效能存在巨大差距,前些时间亲历了二回。事情的背景是付出二个非凡程序,将书籍(BookID)推荐给网络朋友(UserID),生成明天引入数据时,有条规则是一样书籍三日内不可能引入给同一网络朋友。

  命名空间System.Collections.Generic中有几个12分重大,而且常用的泛型集结类,它们各自是Dictionary<TKey,TValue>字典和List<T>列表。Dictionary字典经常用于保存键/值对的多寡,而List列表通中用于保存可通过索引访问的目的的强类型列表。上面来总括一下,用代码来演示怎么开首化,扩大,修改,删除和遍历元素。

Dictionary<TKey,TValue>字典

  代码如下:

namespace DictionaryDemo1
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建Dictionary<TKey,TValue>对象
            Dictionary<string, string> openWith = new Dictionary<string, string>();

            //添加元素到对象中,共有两种方法。注意,字典中的键不可以重复,但值可以重复。
            //方法一:使用对象的Add()方法
            openWith.Add("txt", "notepad.exe");
            openWith.Add("bmp", "paint.exe");
            openWith.Add("dib", "paint.exe");
            openWith.Add("rtf", "wordpad.exe");

            //方法二:使用索引器Indexer
            //openWith["txt"] = "notepad.exe";
            //openWith["bmp"] = "paint.exe";
            //openWith["dib"] = "paint.exe";
            //openWith["rtf"] = "wordpad.exe";

            //增加元素,注意增加前必须检查要增加的键是否存在使用ContainsKey()方法
            if (!openWith.ContainsKey("ht"))
            {
                openWith.Add("ht", "hypertrm.exe");//或openWith["ht"] = "hypertrm.exe";
                Console.WriteLine("增加元素成功!Key={0},Value={1}","ht",openWith["ht"]);
            }

            //删除元素,使用Remove()方法
            if (openWith.ContainsKey("rtf"))
            {
                openWith.Remove("rtf");
                Console.WriteLine("删除元素成功!键为rtf");
            }

            if (!openWith.ContainsKey("rtf"))
            {
                Console.WriteLine("Key=\"rtf\"的元素找不到!");
            }

            //修改元素,使用索引器
            if (openWith.ContainsKey("txt"))
            {
                openWith["txt"] = "notepadUpdate.exe";
                Console.WriteLine("修改元素成功!Key={0},Value={1}", "txt", openWith["txt"]);
            }

            //遍历元素,因为该类实现了IEnumerable接口,所以可以使用foreach语句,注意元素类型是 KeyValuePair(Of TKey, TValue)
            foreach (KeyValuePair<string, string> kvp in openWith)
            {
                Console.WriteLine("Key={0},Value={1}",kvp.Key,kvp.Value);
            }

            Console.WriteLine("遍历元素完成!");
            Console.ReadKey();
        }
    }
}

  程序输出结果:

4858.com 1

        
同一书籍二二十三日内不能够引入给同一网上好友规则的兑现是先后不断优化的进度,第一版先后是从来取数据库,依据BookID+UserID查询三7日内有无记录,有的话不进行分红。但随着数据量的附加,程序运维时间越来越长,于是从头优化。第二遍优化是把具备二七日内的数据抽出来,放到List<T>中,然后再内部存款和储蓄器中进行搜索,发掘那样功能只是稍有加强,但不料定。第一次优化利用了Dictionary<TKey,
电视机alue>,意外的意识意义不是一般的好,程序成效提升了几倍。

Dictionary<TKey,TValue>字典

  代码如下:

4858.com 2

namespace DictionaryDemo1
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建Dictionary<TKey,TValue>对象
            Dictionary<string, string> openWith = new Dictionary<string, string>();

            //添加元素到对象中,共有两种方法。注意,字典中的键不可以重复,但值可以重复。
            //方法一:使用对象的Add()方法
            openWith.Add("txt", "notepad.exe");
            openWith.Add("bmp", "paint.exe");
            openWith.Add("dib", "paint.exe");
            openWith.Add("rtf", "wordpad.exe");

            //方法二:使用索引器Indexer
            //openWith["txt"] = "notepad.exe";
            //openWith["bmp"] = "paint.exe";
            //openWith["dib"] = "paint.exe";
            //openWith["rtf"] = "wordpad.exe";

            //增加元素,注意增加前必须检查要增加的键是否存在使用ContainsKey()方法
            if (!openWith.ContainsKey("ht"))
            {
                openWith.Add("ht", "hypertrm.exe");//或openWith["ht"] = "hypertrm.exe";
                Console.WriteLine("增加元素成功!Key={0},Value={1}","ht",openWith["ht"]);
            }

            //删除元素,使用Remove()方法
            if (openWith.ContainsKey("rtf"))
            {
                openWith.Remove("rtf");
                Console.WriteLine("删除元素成功!键为rtf");
            }

            if (!openWith.ContainsKey("rtf"))
            {
                Console.WriteLine("Key=\"rtf\"的元素找不到!");
            }

            //修改元素,使用索引器
            if (openWith.ContainsKey("txt"))
            {
                openWith["txt"] = "notepadUpdate.exe";
                Console.WriteLine("修改元素成功!Key={0},Value={1}", "txt", openWith["txt"]);
            }

            //遍历元素,因为该类实现了IEnumerable接口,所以可以使用foreach语句,注意元素类型是 KeyValuePair(Of TKey, TValue)
            foreach (KeyValuePair<string, string> kvp in openWith)
            {
                Console.WriteLine("Key={0},Value={1}",kvp.Key,kvp.Value);
            }

            Console.WriteLine("遍历元素完成!");
            Console.ReadKey();
        }
    }
}

4858.com 3

  程序输出结果:

4858.com 4

回去顶部

List<T>列表

  代码如下:

namespace ListDemo1
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建List<T>列表对象
            List<string> dinosaurs = new List<string>();

            //增加元素到列表(或称为初始化),注意初始化时不能使用索引器,因为没有增加元素之前list列表是空的
            dinosaurs.Add("Tyrannosaurus");
            dinosaurs.Add("Amargasaurus");
            dinosaurs.Add("Mamenchisaurus");
            dinosaurs.Add("Deinonychus");
            dinosaurs.Add("Compsognathus");

            //一个重要属性
            Console.WriteLine("列表中的元素数为: {0}", dinosaurs.Count);//获取 List 中实际包含的元素数


            //插入元素,使用Insert()方法
            dinosaurs.Insert(2, "Compsognathus");//将元素插入到指定索引处,原来此位置的元素后移
            Console.WriteLine("在索引为2的位置插入了元素{0}",dinosaurs[2]);

            //删除元素,使用Remove()方法
            dinosaurs.Remove("Compsognathus");//从 List 中移除特定对象的第一个匹配项
            Console.WriteLine("删除第一个名为Compsognathus的元素!");

            //修改元素,使用索引器
            dinosaurs[0] = "TyrannosaurusUpdate";
            Console.WriteLine("修改索引为0的元素成功!");

            //遍历元素,使用foreach语句,元素类型为string
            foreach (string dinosaur in dinosaurs)
            {
                Console.WriteLine(dinosaur);
            }

            Console.WriteLine("遍历元素完成!");
            Console.ReadKey();
        }
    }
}

  程序输出结果:

4858.com 5

       
 上面是伪代码,简化了程序代码,只是为注明List和Dictionary功用的差别,并不有所实际意义。

List<T>列表

  代码如下:

4858.com 6

namespace ListDemo1
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建List<T>列表对象
            List<string> dinosaurs = new List<string>();

            //增加元素到列表(或称为初始化),注意初始化时不能使用索引器,因为没有增加元素之前list列表是空的
            dinosaurs.Add("Tyrannosaurus");
            dinosaurs.Add("Amargasaurus");
            dinosaurs.Add("Mamenchisaurus");
            dinosaurs.Add("Deinonychus");
            dinosaurs.Add("Compsognathus");

            //一个重要属性
            Console.WriteLine("列表中的元素数为: {0}", dinosaurs.Count);//获取 List 中实际包含的元素数


            //插入元素,使用Insert()方法
            dinosaurs.Insert(2, "Compsognathus");//将元素插入到指定索引处,原来此位置的元素后移
            Console.WriteLine("在索引为2的位置插入了元素{0}",dinosaurs[2]);

            //删除元素,使用Remove()方法
            dinosaurs.Remove("Compsognathus");//从 List 中移除特定对象的第一个匹配项
            Console.WriteLine("删除第一个名为Compsognathus的元素!");

            //修改元素,使用索引器
            dinosaurs[0] = "TyrannosaurusUpdate";
            Console.WriteLine("修改索引为0的元素成功!");

            //遍历元素,使用foreach语句,元素类型为string
            foreach (string dinosaur in dinosaurs)
            {
                Console.WriteLine(dinosaur);
            }

            Console.WriteLine("遍历元素完成!");
            Console.ReadKey();
        }
    }
}

4858.com 7

  程序输出结果:

4858.com 8

 

来源:

4858.com 94858.com 10

    /// <summary>
    /// 集合类效率测试
    /// </summary>
    public class SetEfficiencyTest
    {
        static List<TestModel> todayList = InitTodayData();
        static List<TestModel> historyList = InitHisoryData();

        public static void Run()
        {
            CodeTimer.Time("ListTest", 1, ListTest);
            CodeTimer.Time("DictionaryTest", 1, DictionaryTest);
        }

        public static void ListTest()
        {
            List<TestModel> resultList = todayList.FindAll(re =>
             {
                 if (historyList.Exists(m => m.UserID == re.UserID && m.BookID == re.BookID))
                 {
                     return false;
                 }
                 return true;
             });
        }

        public static void DictionaryTest()
        {
            Dictionary<int, List<string>> bDic = new Dictionary<int, List<string>>();
            foreach (TestModel obj in historyList)
            {
                if (!bDic.ContainsKey(obj.UserID))
                {
                    bDic.Add(obj.UserID, new List<string>());
                }
                bDic[obj.UserID].Add(obj.BookID);
            }

            List<TestModel> resultList = todayList.FindAll(re =>
            {
                if (bDic.ContainsKey(re.UserID) && bDic[re.UserID].Contains(re.BookID))
                {
                    return false;
                }
                return true;
            });
        }

        /// <summary>
        /// 初始化数据(今日)
        /// </summary>
        /// <returns></returns>
        public static List<TestModel> InitTodayData()
        {
            List<TestModel> list = new List<TestModel>();
            for (int i = 0; i < 10000; i++)
            {
                list.Add(new TestModel() { UserID = i, BookID = i.ToString() });
            }
            return list;
        }

        /// <summary>
        /// 初始化数据(历史)
        /// </summary>
        /// <returns></returns>
        public static List<TestModel> InitHisoryData()
        {
            List<TestModel> list = new List<TestModel>();
            Random r = new Random();
            int loopTimes = 60000;
            for (int i = 0; i < loopTimes; i++)
            {
                list.Add(new TestModel() { UserID = r.Next(0, loopTimes), BookID = i.ToString() });
            }
            return list;
        }

        /// <summary>
        /// 测试实体
        /// </summary>
        public class TestModel
        {
            /// <summary>
            /// 用户ID
            /// </summary>
            public int UserID { get; set; }

            /// <summary>
            /// 书ID
            /// </summary>
            public string BookID { get; set; }
        }
    }

View Code

4858.com,         输出如下:

         4858.com 11

       
 真是意想不到,两者效能相差这么多。接下来商量下互相反差巨大的缘故。

         List<T>.Exists()函数的达成: 

4858.com 124858.com 13

        public bool Exists(Predicate<T> match)
        {
            return this.FindIndex(match) != -1;
        }

        public int FindIndex(Predicate<T> match)
        {
            return this.FindIndex(0, this._size, match);
        }
        public int FindIndex(int startIndex, int count, Predicate<T> match)
        {
            if (startIndex > this._size)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
            }
            if (count < 0 || startIndex > this._size - count)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count);
            }
            if (match == null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
            }
            int num = startIndex + count;
            for (int i = startIndex; i < num; i++)
            {
                if (match(this._items[i]))
                {
                    return i;
                }
            }
            return -1;
        }

View Code

         List<T>.Exists
本质是通过循环查寻觅该条数据,每三回的调用都会重头循环,所以功效相当的低。显明,那是不可取的。

         Dictionary<TKey, TValue>.ContainsKey()函数的贯彻:    

4858.com 144858.com 15

        public bool ContainsKey(TKey key)
        {
            return this.FindEntry(key) >= 0;
        }

        // System.Collections.Generic.Dictionary<TKey, TValue>
        private int FindEntry(TKey key)
        {
            if (key == null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }
            if (this.buckets != null)
            {
                int num = this.comparer.GetHashCode(key) & 2147483647;
                for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.entries[i].next)
                {
                    if (this.entries[i].hashCode == num && this.comparer.Equals(this.entries[i].key, key))
                    {
                        return i;
                    }
                }
            }
            return -1;
        }

View Code

         Dictionary<TKey,
TValue>.ContainsKey() 内部是经过Hash查找完毕的,所以功用比List超出多数。
  

         最终,给出MSDN上的建议:

       
 1.假如须要尤其快地抬高、删除和查找项目,而且不爱慕集结中项目标逐一,那么首先应当思虑采用System.Collections.Generic.Dictionary<TKey,
电视alue>(或然你正在利用 .NET Framework 一.x,能够设想
Hashtable)。四个基本操作(增添、删除和富含)都可火速操作,尽管会集包蕴上百万的门类。

       
 二.只要您的选用形式很少供给删除和大气增进,而首要的是维持集合的次第,那么您还能选拔List<T>。即使寻找速度也许极慢(因为在搜索指标项目时要求遍历基础数组),但可以保障集结会保持一定的1一。

         三.您能够选拔 Queue<T> 完结先进先出 (FIFO) 顺序或
Stack<T> 落成后进先出 (LIFO) 顺序。纵然 Queue<T> 和
Stack<T>
都援救枚举集结中的全数种类,但前者只帮助在终极插入和从早先删除,而后人只帮忙从起始插入和删除。

         肆.若是急需在完毕高效插入的同时保持顺序,那么使用新的
LinkedList<T> 群集可支持你提升品质。与 List<T>
分化,LinkedList<T> 是当做动态分配的对象链完结。与 List<T>
比较,在集合中间插入对象只供给立异七个一而再和增加新品类。从性质的角度来看,链接列表的弱点是废物搜聚器会大增其运动,因为它必须遍历整个列表以保证未有目标未有被放出。其余,由于每一个节点相关的开销以及种种节点在内部存款和储蓄器中的地方等原因,大的链接列表可能会产出质量难点。就算将项目插入到
LinkedList<T> 的实在操作比在 List<T>
中插入要快得多,不过找到要插入新值的特定岗位仍需遍历列表并找到科学的职责。

          参考资料:CLQashqai 完全介绍:
最棒实行集合, List和hashtable之查找成效

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有