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("\nBMP 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

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM