溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#字典的使用方法是什么

發布時間:2022-04-12 13:55:33 來源:億速云 閱讀:205 作者:iii 欄目:開發技術

這篇文章主要介紹“C#字典的使用方法是什么”,在日常操作中,相信很多人在C#字典的使用方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C#字典的使用方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

字典表示一種復雜的數據結構,這種數據結構允許按照某個鍵來訪問元素。字典也稱為映射或散列表。
字典的主要特性是能根據鍵快速查找值。也可以自由添加和刪除元素,這有點像List<T>,但沒有在內存中移動后續元素的性能開銷。
下圖是一個簡化表示,鍵會轉換位一個散列。利用散列創建一個數字,它將索引和值關聯起來。然后索引包含一個到值的鏈接。一個索引項可以關聯多個值,索引可以存儲為一個樹型結構。

C#字典的使用方法是什么

.NET Framework提供了幾個字典類。最主要的類是Dictionary<TKey,TValue>。

1.鍵的類型

用作字典中的鍵的類型必須重寫Object類的GetHashCode()方法。只要字典類需要確定元素的位置,它就要調用GetHashCode()方法。GetHashCode()方法返回的int有字典用于計算在對應位置放置元素的索引。后面介紹這個算法,現在只需要知道它涉及素數,所以字典的容量是一個素數。
GetHashCode()方法的實現代碼必須滿足的要求:

  • *相同的對象應總是返回相同的值

  • *不同的對象可以返回相同的值

  • *它應執行的比較快,計算的開銷不大

  • *它不能拋出異常

  • *它應至少使用一個實例字段

  • *散列代碼值應平均分布在int可以存儲的這個數字范圍上

  • *散列代碼最好在對象的生存期中不發生變化

字典的性能取決于GetHashCode()方法的實現代碼。
散列代碼值應平均分布在int可以存儲的這個數字范圍上的原因:
如果兩個鍵返回的散列代碼值會得到相同的索引,字典類就必須尋找最近的可用空閑位置來存儲第二個數據項,這需要進行一定的搜索,以便以后檢索這一項。顯然這會降低性能,如果在排序的時候許多鍵都有相同的索引這中沖突會更可能出現。根據Microsoft的算法工作方式,當計算出來的散列代碼值平均分布在int.MinValue和int.MaxValue之間時,這種風險會降到最低。
除了實現GetHashCode()方法之外,鍵類型還必須實現IEquatable<T>.Equals()方法,或重寫Object.Equals()方法。0因為不同的鍵對象可能返回相同的散列代碼,所以字典使用Equals()方法來比較鍵。字典檢查兩個鍵A和B是否相等,并調用A.Equals(B)方法。這表示必須確保下述條件總是成立:
如果A.Equals(B)返回true,則A.GetHashCode()和B.GetHashCode()總是返回相同的散列代碼。
這聽起來有點奇怪,但它很重要。如果上述條件不成立,這個字典還能工作,但會出現,把一個對象放在字典中后,就再也檢索不到它,或者返回了錯誤的項。
所以,如果為Equals()方法提供了重寫版本,但沒提供GetHashCode()方法的重寫版本,C#編譯器會顯示一個警告。
對于System.Object,這個條件為true,因為Equals()方法只是比較引用,GetHashCode()方法實際上返回一個僅基于對象地址的散列代碼。這說明,如果散列表基于一個鍵,而該鍵沒有重寫這些方法,這個散列表可以工作,但只有對象完全相同,鍵才被認為是相等的。也就是說,把一個對象放在字典中時,必須將它與該鍵的引用關聯起來。也不能以后用相同的值實例化另一個鍵對象。如果沒有重寫Equals()方法和GetHashCode()方法,在字典中使用類型時就不太方便。
System.String實現了IEquatable接口,并重載了GetHashCode()方法。Equals()方法提供了值的比較,GetHashCode()方法根據字符串的值返回一個散列代碼。因此,在字典中把字符串用在鍵很方便。
數字類型(如Int32)也實現了IEquatable接口,并重載了GetHashCode()方法。但是這些類型返回的散列代碼只能映射到值上。如果希望用作鍵的數字本身沒有分布在可能的整數值范圍內,把整數用作鍵就不能滿足鍵值的平均分布規則,于是不能獲得最佳的性能。Int32并不適合在字典中使用。
如果需要使用的鍵類型沒有實現IEquatable接口,并根據存儲在字典中的鍵值重載GetHashCode()方法,就可以創建一個實現IEqualityComparer<T>接口的比較器。IEqualityComparer<T>接口定義了GetHashCode()方法和Equals()方法,并將傳遞的對象作為參數,這樣可以提供與對象類型不同的實現方式。

2.演示字典

創建一個員工ID(EmployeeId)結構,用作字典的鍵。存儲在字典中的數據是Employee類型的對象。
該結構的成員是表示員工的一個前綴字符和一個數字。這兩個變量都是只讀的,只能在構造函數中初始化。字典中的鍵不應改變,這是必須保證的?!?/p>

      public struct EmployeeId : IEquatable<EmployeeId>
          {
            private readonly char prefix;
            private readonly int number;

            public EmployeeId(string id)
            {
              Contract.Requires<ArgumentNullException>(id != null);

              prefix = (id.ToUpper())[0];
              int numLength = id.Length - 1;
              try
              {
                number = int.Parse(id.Substring(1, numLength > 6 ? 6 : numLength));
              }
              catch (FormatException)
              {
                throw new Exception("Invalid EmployeeId format");
              }
            }

            public override string ToString()
            {
              return prefix.ToString() + string.Format("{0,6:000000}", number);
            }
            
            //由于沒有填滿整數取值范圍,GetHashCode方法將數字向左移動16位,再與原來的數字進行異或操作,
            //最后將結果乘以16進制數0x15051505。這樣,散列代碼在整數取值區域上的分布就很均勻。
            public override int GetHashCode()
            {
              return (number ^ number << 16) * 0x15051505;
            }

            public bool Equals(EmployeeId other)
            {
              if (other == null) return false;

              return (prefix == other.prefix && number == other.number);
            }
            //比較兩個EmployeeId對象的值
            public override bool Equals(object obj)
            {
              return Equals((EmployeeId)obj);
            }

            public static bool operator ==(EmployeeId left, EmployeeId right)
            {
              return left.Equals(right);
            }

            public static bool operator !=(EmployeeId left, EmployeeId right)
            {
              return !(left == right);
            }
          }
    
          public class Employee
          {
            private string name;
            private decimal salary;
            private readonly EmployeeId id;

            public Employee(EmployeeId id, string name, decimal salary)
            {
              this.id = id;
              this.name = name;
              this.salary = salary;
            }

            public override string ToString()
            {
              return String.Format("{0}: {1, -20} {2:C}",
                    id.ToString(), name, salary);
            }
          }

客戶端代碼:

    static void Main()
        {
            //構造函數指定了31個元素的容量。容量一般是素數。
            //如果指定了一個不是素數的值,Dictionary<TKey,TValue>類會使用指定的整數后面緊接著的一個素數
          var employees = new Dictionary<EmployeeId, Employee>(31);

          var idTony = new EmployeeId("C3755");
          var tony = new Employee(idTony, "Tony Stewart", 379025.00m);
          employees.Add(idTony, tony);
          Console.WriteLine(tony);

          var idCarl = new EmployeeId("F3547");
          var carl = new Employee(idCarl, "Carl Edwards", 403466.00m);
          employees.Add(idCarl, carl);
          Console.WriteLine(carl);

          var idKevin = new EmployeeId("C3386");
          var kevin = new Employee(idKevin, "Kevin Harwick", 415261.00m);
          employees.Add(idKevin, kevin);
          Console.WriteLine(kevin);

          var idMatt = new EmployeeId("F3323");
          var matt = new Employee(idMatt, "Matt Kenseth", 1589390.00m);
          employees[idMatt] = matt;
          Console.WriteLine(matt);

          var idBrad = new EmployeeId("D3234");
          var brad = new Employee(idBrad, "Brad Keselowski", 322295.00m);
          employees[idBrad] = brad;
          Console.WriteLine(brad);
        }

3.Lookup類

Dictionary<TKey,TValue>類支持每個鍵關聯一個值。Lookup<TKey,TElement>類把鍵映射到一個值集上。這個類在程序集System.Core中實現,用System.Linq定義。
Lookup<TKey,TElement>類不能像一般的字典那樣創建,必須調用ToLookup()方法,該方法返回一個Lookup<TKey,TElement>對象。ToLookup()方法是一個擴展方法,它可以用于實現了IEnumerable<T>接口的所有類。
ToLookup()方法需要一個Func<TSource,Tkey>,Func<TSource,Tkey>定義了選擇器?! ?/p>

    static void Main()
    {
          var racers = new List<Racer>();
          racers.Add(new Racer(26, "Jacques", "Villeneuve", "Canada", 11));
          racers.Add(new Racer(18, "Alan", "Jones", "Australia", 12));
          racers.Add(new Racer(11, "Jackie", "Stewart", "United Kingdom", 27));
          racers.Add(new Racer(15, "James", "Hunt", "United Kingdom", 10));
          racers.Add(new Racer(5, "Jack", "Brabham", "Australia", 14));
          //國家相同的對象關聯到一個鍵
          var lookupRacers = racers.ToLookup(r => r.Country);

          foreach (Racer r in lookupRacers["Australia"])
          {
            Console.WriteLine(r);
          }
    }

輸出:

  Alan Jones
  Jack Brabham

4.有序字典

SortedDictionary<TKey,TValue>類是一個二叉搜索樹,其中的元素根據鍵來排序。該鍵類型必須實現IComparable<TKey>接口。
如果鍵的類型不能排序,還可以創建一個實現了IComparer<TKey>接口的比較器,將比較器用作有序字典的構造函數的一個參數。
SortedDictionary<TKey,TValue>和有序列表SortedList<TKey,TValue>的區別:

  • *SortedList<TKey,TValue>類使用的內存比SortedDictionary<TKey,TValue>少。

  • *SortedDictionary<TKey,TValue>元素的插入和刪除操作比較快。

  • *在用已排序好的數據填充集合時,若不需要改變容量,ortedList<TKey,TValue>比較快。

到此,關于“C#字典的使用方法是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女