• C#基础知识之Dictionary


    最近使用了Dictionary,出现了意想不到的错误,先记录一下自己遇到的问题以及目前我的解决方法,然后温习一下Dictionary的基础用法。
    一、自己遇到的问题
      1、代码如下:

    namespace DictionaryExample
    {
        class Program
        {
            static void Main(string[] args)
            {
                string[] pedlarArray = {"小明","小王","小红"};
                Dictionary<Apple, string[]> appleMessageDict = new Dictionary<Apple, string[]>();
                appleMessageDict.Add(new Apple() {
                    Quantity = 20,
                    Price = 5
                }, pedlarArray);            
                Console.WriteLine("appleMessageDict.Values.Count:{0}", appleMessageDict.Count);
                Console.WriteLine("appleMessageDict.Keys.Count:{0}", appleMessageDict.Keys.Count);
                Console.WriteLine("appleMessageDict.Values.Count:{0}", appleMessageDict.Values.Count);
                Console.ReadKey();
            }
        }
    
        public class Apple
        {
            private int _quantity;
            private float _price;
            public int Quantity
            {
                get { return _quantity; }
                set
                {
                    _quantity = value;
                }
            }
    
            public float Price
            {
                get { return _price; }
                set
                {
                    _price = value;
                }
            }
    
            public Apple()
            {
            }
        }
    }   
    View Code

      运行结果:

      

      2、原因分析
        代码里面的字典AppleMessageDict的value是字符串数组类型,key是一个类类型。为什么数量都是1呢?通过分析我发现appleMessageDict.Count、appleMessageDict.Keys.Count、appleMessageDict.Values.Count这三个统计count的方式仅仅是针对于字典本身的统计,无关key/value是什么类型,仅仅是统计字典包含多少键值对。如果每个键值对中的key或者value是集合,想要知道key或者value的数量,需要另外处理。
      3、目前我的解决方法

    static void Main(string[] args)
     {
        int length = 0;
        string[] pedlarArray = { "小明", "小王", "小红" };
        Dictionary<Apple, string[]> appleMessageDict = new Dictionary<Apple, string[]>();
        appleMessageDict.Add(new Apple()
        {
            Quantity = 20,
            Price = 5
        }, pedlarArray);
        foreach (KeyValuePair<Apple, string[]> pair in appleMessageDict)//目前只能循环统计字典的数量
        {
            length += pair.Value.Length;
        }
        Console.WriteLine("appleMessageDict的数量:{0}", length);
        //Console.WriteLine("appleMessageDict.Values.Count:{0}", appleMessageDict.Count);
        //Console.WriteLine("appleMessageDict.Keys.Count:{0}", appleMessageDict.Keys.Count);
        //Console.WriteLine("appleMessageDict.Values.Count:{0}", appleMessageDict.Values.Count);
        Console.ReadKey();
    }                 
    View Code

    二、Dictionary的基础知识
      1、Dictionary的概念
        Dictionary<[key], [value]>是一个泛型,Dictionary是一种变种的HashTable,是一个表示键和值的集合。
      2、Dictionary的特点
        键必须是唯一的,而值不需要唯一的 。键和值都可以是任何类型。通过一个键读取一个值的时间是接近O(1) 。
      3、Dictionary的构造函数 

      

      

      (1)Dictionary<TKey,TValue>()构造函数:初始化 Dictionary<TKey,TValue> 类的新实例,该实例为空,具有默认的初始容量(Dictionary的默认大小为3)并为键类型使用默认的相等比较器。key不可重复,区分大小写

    static void Main(string[] args)
    {
        #region Dictionary构造函数  (key不可重复,区分大小写)  
        Console.WriteLine("==========Dictionary普通构造函数! key不可重复,区分大小写===========");
        Dictionary<string, string> dict =new Dictionary<string, string>();
        dict.Add("a","1");
        try
        {
             dict.Add("A", "1");
            foreach (KeyValuePair<string,string> item in dict)
            {
                Console.WriteLine("Key:{0},Value:{1}", item.Key,item.Value);
            }
        }
        catch (ArgumentException)
        {
            Console.WriteLine("键A已经存在!");
        }
        Console.WriteLine("输入任意值,执行下一个构造函数:");
        Console.ReadKey();   
    }         
    View Code

        运行结果

        


      (2)Dictionary<TKey,TValue>(IEqualityComparer<TKey>)构造函数:初始化 Dictionary<TKey,TValue> 类的新实例,该实例为空,具有默认的初始容量(Dictionary的默认大小为3)并使用指定的 IEqualityComparer<T>。key不可重复,不区分大小写

    #region Dictionary 构造函数,key不可重复,不区分大小写
    Console.WriteLine("==========Dictionary构造函数! key不可重复,不区分大小写===========");
    Dictionary<string, string> dict1 = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
    dict1.Add("a", "1");
    try
    {
        dict1.Add("A", "1");
    }
    catch (ArgumentException)
    {
        Console.WriteLine("键A已经存在!");
    }
    Console.WriteLine("输入任意值,执行下一个构造函数:");
    Console.ReadKey();
    #endregion  
    View Code

         

        运行结果

        

        (3)Dictionary<TKey,TValue>(IDictionary<TKey,TValue>)构造函数:初始化 Dictionary<TKey,TValue> 类的新实例,该实例包含从指定的 IDictionary<TKey,TValue> 复制的元素并为键类型使用默认的相等比较器。

    #region Dictionary构造函数 通过SortedDictionary初始化Dictionary
    Console.WriteLine("==========Dictionary构造函数!通过SortedDictionary初始化Dictionary===========");
    SortedDictionary<string, string> sortDict =new SortedDictionary<string, string>();
    sortDict.Add("txt", "notepad.exe");
    sortDict.Add("bmp", "paint.exe");
    sortDict.Add("dib", "paint.exe");
    sortDict.Add("rtf", "wordpad.exe");
    Dictionary<string, string> copyDict = new Dictionary<string, string>(sortDict);
    foreach (KeyValuePair<string,string> item in copyDict)
    {
        Console.WriteLine("key:{0},value:{1}",item.Key,item.Value);
    }
    Console.WriteLine("输入任意值,执行下一个构造函数:");
    Console.ReadKey();
    #endregion
    View Code

           

        运行结果

        


        (4)Dictionary<TKey,TValue>(Int32)构造函数:初始化 Dictionary<TKey,TValue> 类的新实例,该实例为空,具有指定的初始容量并为键类型使用默认的相等比较器。
        
          字典默认容量是3,可以初始化字典容量,如果初始化的容量不满足实际需求,将自动增加容量(自动扩容的规则将在下边专门介绍)。如果可以估计集合的大小,指定的初始容量,则无需要执行多个大小调整操作

    #region Dictionary 构造函数 初始化Dictionary的大小容量  
    //字典默认容量是3,可以初始化字典容量,如果初始化的容量不满足实际需求,将自动增加容量。如果可以估计集合的大小,指定的初始容量,则无需要执行多个大小调整操作
    Console.WriteLine("==========Dictionary 构造函数 初始化Dictionary的大小容量===========");
    Dictionary<string, string> capacityDict = new Dictionary<string, string>(2);
    capacityDict.Add("txt", "notepad.exe");
    capacityDict.Add("bmp", "paint.exe");
    capacityDict.Add("dib", "paint.exe");
    capacityDict.Add("rtf", "wordpad.exe");            
    foreach (KeyValuePair<string, string> item in copyDict)
    {
        Console.WriteLine("key:{0},value:{1}", item.Key, item.Value);
    }
    Console.WriteLine("输入任意值,执行下一个构造函数:");
    Console.ReadKey();
    #endregion   
    View Code

        运行结果

        


        (5)Dictionary<TKey,TValue>(IDictionary<TKey,TValue>, IEqualityComparer<TKey>)构造函数:使用不区分大小写的比较器创建一个新的字典和填充从一个字典,其中使用区分大小写的比较器,如本示例所示的条目时如果输入的字典具有仅大小写不同的键,则会发生异常。

    #region Dictionary 构造函数 使用不区分大小写的比较器创建一个新的字典和填充从一个字典
    //使用不区分大小写的比较器创建一个新的字典和填充从一个字典,其中使用区分大小写的比较器,如本示例所示的条目时如果输入的字典具有仅大小写不同的键,则会发生异常。
    Console.WriteLine("==========Dictionary 构造函数 使用不区分大小写的比较器创建一个新的字典和填充从一个字典===========");
    SortedDictionary<string, string> sortDict1 = new SortedDictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
    sortDict1.Add("txt", "notepad.exe");
    sortDict1.Add("bmp", "paint.exe");
    sortDict1.Add("dib", "paint.exe");
    sortDict1.Add("rtf", "wordpad.exe");
    Dictionary<string, string> copyDict1 = new Dictionary<string, string>(sortDict1,StringComparer.CurrentCultureIgnoreCase);
    foreach (KeyValuePair<string, string> item in copyDict1)
    {
        Console.WriteLine("key:{0},value:{1}", item.Key, item.Value);
    }
    Console.WriteLine("输入任意值,执行下一个构造函数:");
    Console.ReadKey();
    #endregion  #region Dictionary 构造函数 使用不区分大小写的比较器创建一个新的字典和填充从一个字典
    //使用不区分大小写的比较器创建一个新的字典和填充从一个字典,其中使用区分大小写的比较器,如本示例所示的条目时如果输入的字典具有仅大小写不同的键,则会发生异常。
    Console.WriteLine("==========Dictionary 构造函数 使用不区分大小写的比较器创建一个新的字典和填充从一个字典===========");
    SortedDictionary<string, string> sortDict1 = new SortedDictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
    sortDict1.Add("txt", "notepad.exe");
    sortDict1.Add("bmp", "paint.exe");
    sortDict1.Add("dib", "paint.exe");
    sortDict1.Add("rtf", "wordpad.exe");
    Dictionary<string, string> copyDict1 = new Dictionary<string, string>(sortDict1,StringComparer.CurrentCultureIgnoreCase);
    foreach (KeyValuePair<string, string> item in copyDict1)
    {
        Console.WriteLine("key:{0},value:{1}", item.Key, item.Value);
    }
    Console.WriteLine("输入任意值,执行下一个构造函数:");
    Console.ReadKey();
    #endregion  
    View Code

          
        运行结果

        

        (6)Dictionary<TKey,TValue>(Int32, IEqualityComparer<TKey>)构造函数:初始化 Dictionary<TKey,TValue> 类的新实例,该实例为空,具有指定的初始容量并使用指定的 IEqualityComparer<T>。

    #region 
    Dictionary<string, string> dict3 =new Dictionary<string, string>(5,StringComparer.CurrentCultureIgnoreCase);           
    dict3.Add("txt", "notepad.exe");
    dict3.Add("bmp", "paint.exe");
    dict3.Add("DIB", "paint.exe");
    dict3.Add("rtf", "wordpad.exe");
    try
    {
        dict3.Add("BMP", "paint.exe");
    }
    catch (ArgumentException)
    {
        Console.WriteLine("
    BMP is already in the dictionary.");
    }   
    foreach (KeyValuePair<string, string> kvp in dict3)
    {
        Console.WriteLine("Key = {0}, Value = {1}", kvp.Key,kvp.Value);
    }
    #endregion   
    View Code

       

        运行结果

        

        (7)Dictionary<TKey,TValue>(SerializationInfo, StreamingContext)构造函数:用序列化数据初始化 Dictionary<TKey,TValue> 类的新实例。
    ===============List和Dictionary扩容规则======================
          List和Dictionary的构造函数都有一个入参为int的构造函数:public Dictionary(int capacity);和public List(int capacity);capacity用来指定List和Dictionary的初始容量。List和Dictionary的内部实现方式都是使用数组,因为数组的容量是固定的,所以初始化的时候就会对其申请内存,List的默认大小为4,Dictionary的默认大小为3。如果不指定初始化容量,系统会默认创建。当往容器里Add数据时,如果当前数组已满,就会新创建一块两倍于当前数组长度的内存,把原有数据copy到新内存中,再继续往里添加。
          举个例子,创建一个没指定初始容量的List后,依次往里面添加了12个元素,内存是这样分配的:首先默认分配了一块长度为4个List元素的内存给List数组,当添加到第五个时,发现长度不足,所以会分配4*2=8的内存,把原有的4个数据拷贝到新内存块中并把第五个元素添加到末尾;当添加到第九个时,也会重新分配一个8*2=16的内存,把原有的8个数据拷贝到新内存块中并把第9个元素添加到末尾;所以最终List数组的长度为16,里面存放了12个元素,共分配了三次内存,进行了两次的内存拷贝。
          Dictionary容量分配规则也是如此。
          所以合理的指定初始容量,可以减少内存的分配和拷贝次数,甚至还能节省内存空间。
    ================================================================
      4、Dictionary的常用属性
        

      5、Dictionary的方法
        

        (1)添加元素
          第一种方式:通过Add()添加元素
      

    Dictionary<string, string> messageDict = new Dictionary<string, string>();
    for (int i = 0; i < 10; i++)
    {
        messageDict.Add("key"+i,"value"+i);
    }    
    

      


          第二种方式(推荐):通过中括号添加元素
          

    Dictionary<string, string> messageDict = new Dictionary<string, string>();
    for (int i = 0; i < 10; i++)
    {
        messageDict["key" + i]="value"+i;
    }   
    

      

          为什么我们推荐第二种方式呢?我们知道字典的键值不可重复(不使用StringComparer.CurrentCultureIgnoreCase指定的情况下),使用Add()方式,如果存在相同的键,会直接抛出ArgumentException异常。而使用第二种方式,如果存在相同的键,只要key不是null,就会进行改写,就不会出现异常。
        (2)查找元素:第一种方式:通过key查找元素

    static void Main(string[] args)
    {
        Dictionary<string, string> messageDict = new Dictionary<string, string>();
        for (int i = 0; i < 10; i++)
        {
            messageDict["key" + i]="value"+i;
        }
    
        if (messageDict.ContainsKey("key4"))
        {
            Console.WriteLine("key是{0},value是{1}","key4",messageDict["key4"]);
        }
        Console.ReadKey();
    }        
    View Code

      
        (3)遍历字典:通过KeyValuePair遍历元素     

    static void Main(string[] args)
    {
        Dictionary<string, string> messageDict = new Dictionary<string, string>();
        for (int i = 0; i < 10; i++)
        {
            messageDict["key" + i]="value"+i;
        }
        foreach (KeyValuePair<string,string> item in messageDict)
        {
            Console.WriteLine("key是{0},value是{1}", item.Key,item.Value);
        }
        Console.ReadKey();
    }      
    View Code

       


        (4)仅遍历所有的values    

    static void Main(string[] args)
    {
        Dictionary<string, string> messageDict = new Dictionary<string, string>();
        for (int i = 0; i < 10; i++)
        {
            messageDict["key" + i]="value"+i;
        }
        Dictionary<string, string>.ValueCollection valueCollection =messageDict.Values;
        if (valueCollection!= null&&valueCollection.Count>0)
        {
            foreach (string item in valueCollection)
            {
                Console.WriteLine("value是{0}", item);
            }                
        }
        Console.ReadKey();
    }            
    View Code

        (5)仅遍历所有的keys      

    static void Main(string[] args)
    {
        Dictionary<string, string> messageDict = new Dictionary<string, string>();
        for (int i = 0; i < 10; i++)
        {
            messageDict["key" + i]="value"+i;
        }
        Dictionary<string, string>.KeyCollection keyCollection =messageDict.Keys;
        if (keyCollection != null&& keyCollection.Count>0)
        {
            foreach (string item in keyCollection)
            {
                Console.WriteLine("key是{0}", item);
            }                
        }
        Console.ReadKey();
    }               
    View Code

        (6)通过Remove移除元素

    static void Main(string[] args)
    {
        Dictionary<string, string> messageDict = new Dictionary<string, string>();
        for (int i = 0; i < 10; i++)
        {
            messageDict["key" + i]="value"+i;
        }
        messageDict.Remove("key0");
        foreach (KeyValuePair<string,string> item in messageDict)
        {
            Console.WriteLine("key是{0},value是{1}", item.Key,item.Value);
        }
        Console.ReadKey();
    }     
    View Code

     

     

  • 相关阅读:
    [Python]小甲鱼Python视频第038课(类和对象:继承 )课后题及参考解答
    [Python]小甲鱼Python视频第037课(类和对象:面向对象编程 )课后题及参考解答
    [Python]小甲鱼Python视频第036课(类和对象:给大家介绍对象 )课后题及参考解答
    Session共享
    防止表单重复提交
    Docker安装redis
    Docker安装mysql
    docker-compose常用命令
    Docker常用命令
    Oracle 随机取记录
  • 原文地址:https://www.cnblogs.com/qtiger/p/11176537.html
Copyright © 2020-2023  润新知