iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#集合之字典的用法
  • 587
分享到

C#集合之字典的用法

2024-04-02 19:04:59 587人浏览 安东尼
摘要

字典表示一种复杂的数据结构,这种数据结构允许按照某个键来访问元素。字典也称为映射或散列表。字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List<T&g

字典表示一种复杂的数据结构,这种数据结构允许按照某个键来访问元素。字典也称为映射或散列表。
字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List<T>(https://www.jb51.net/article/244084.htm),但没有在内存中移动后续元素的性能开销。
下图是一个简化表示,键会转换位一个散列。利用散列创建一个数字,它将索引和值关联起来。然后索引包含一个到值的链接。一个索引项可以关联多个值,索引可以存储为一个树型结构。

.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类型的对象。
该结构的成员是表示员工的一个前缀字符和一个数字。这两个变量都是只读的,只能在构造函数中初始化。字典中的键不应改变,这是必须保证的。 

      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>定义了选择器。  

    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>(Https://www.jb51.net/article/244111.htm)的区别:

  • *SortedList<TKey,TValue>类使用的内存比SortedDictionary<TKey,TValue>少。
  • *SortedDictionary<TKey,TValue>元素的插入和删除操作比较快。
  • *在用已排序好的数据填充集合时,若不需要改变容量,ortedList<TKey,TValue>比较快。

到此这篇关于C#集合之字典的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C#集合之字典的用法

本文链接: https://www.lsjlt.com/news/145670.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#集合之字典的用法
    字典表示一种复杂的数据结构,这种数据结构允许按照某个键来访问元素。字典也称为映射或散列表。字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List<T&g...
    99+
    2024-04-02
  • python集合与字典的用法
    python集合与字典的用法 集合: 1.增加  add 2.删除   •del 删除集合          •discard(常用)删除集合中的元素  #删除一个不存在的元素不会报错     •remove 删除一个不存在的元素会报错 ...
    99+
    2023-01-30
    字典 python
  • C#集合之并发集合的用法
    .NET 4 开始,在System.Collection.Concurrent中提供了几个线程安全的集合类。线程安全的集合可防止多个线程以相互冲突的方式访问集合。为了对集合进行线程安...
    99+
    2024-04-02
  • C#集合之集(set)的用法
    包含不重复元素的集合称为“集(set)”。.NET Framework包含两个集HashSet<T>和SortedSet<T>,它们都...
    99+
    2024-04-02
  • C#集合之不变集合的用法
    如果对象可以改变其状态,就很难在多个同时运行的任务中使用。这些集合必须同步。如果对象不能改变器状态,就很容易在多个线程中使用。Microsoft提供了一个新的集合库:Microsof...
    99+
    2024-04-02
  • Python字典、集合之高山流水
    字典dict字典是由大括号{键:值}组成、字典是无序的、字典的键必须是不可变数据类型、不能使用列表作为键,但可以使用元祖作为字典的键。例如: dict_ = {"test":"Hello World"} str_ = "hello" ...
    99+
    2023-01-30
    高山流水 字典 Python
  • C#集合之栈的用法
    栈(Stack)和队列是非常类似的一个容器,只是栈是一个后进先出(LIFO)的容器。栈用Push()方法在栈中添加元素,用Pop()方法获取最近添加的一个元素: Stack<...
    99+
    2024-04-02
  • C#集合之可观察集合的用法
    如果需要集合中的元素何时删除或添加的信息,可以使用ObservableCollection<T>类。这个类是为WPF定义的,这样UI就可以得知集合的变化。这个类在程序集W...
    99+
    2024-04-02
  • Python学习之字典和集合的使用详解
    目录字典简介字典的基本方法字典元素添加获取字典键对应的值字典元素的修改字典元素的删除字典的遍历集合学习集合添加元素集合删除元素统计集合个数,判断元素是否存在,清空集合集合运算字典简介...
    99+
    2024-04-02
  • python基础入门之字典和集合
    目录正文字典集合python 中有6大标准类型: 数字(Number) 字符串(String) 列表(List) 元组(Tumple) 集合(Set) 字典(Dictionary...
    99+
    2024-04-02
  • C#集合之队列的用法
    队列是其元素按照先进先出(FIFO)的方式来处理的集合。队列使用System.Collections.Generic名称空间中的泛型类Queue<T>实现。在内部,Que...
    99+
    2024-04-02
  • C#集合之链表的用法
    LinkedList<T>是一个双向链表,其元素会指向它前面和后面的元素。这样,通过移动到下一个元素可以正向遍历链表,通过移动到前一个元素可以反向遍历链表。 链表在存储...
    99+
    2024-04-02
  • python字典和集合
      1. 字典字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据。python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必须是可哈希的。可哈希表示key必...
    99+
    2023-01-31
    字典 python
  • 元组、字典、集合
    1、作用 存多个值,对比列表来说,元组不可变,主要是用来读。 2、定义 与列表类型比,只不过[ ]换成() t = ()  #本质:t = tuple(())print(t,type(t))  #() <class 'tuple&...
    99+
    2023-01-31
    字典
  • C#集合之列表的用法
    目录1.创建列表2.添加元素3.插入元素4.访问元素5.删除元素6.搜索7.排序8.类型转换9.只读集合.NET Framework为动态列表List提供泛型类List<T&g...
    99+
    2024-04-02
  • Python中的字典与集合
    Dictionary:字典     Set:集合 字典的语法: Dictionary字典(键值对) 语法: dictionary = {key:value,key:value,key n:value n} 与 C# dictionary...
    99+
    2023-01-31
    字典 Python
  • Python中的集合和字典
    目录1 集合2 字典(key:value)1 集合 集合可以使用大括号({})或者set()函数进行创建,但是创建一个空集合必须使用set()函数,而不能用{},大括号是用来创建一个...
    99+
    2024-04-02
  • python元组 字典 集合
    1.列表构建栈的数据结构:栈的特点:先进后出 #!/usr/bin/env python #coding:utf-8 stack = [] info = """ 栈结构 1.入栈 2.出栈 ...
    99+
    2023-01-31
    字典 python
  • C#集合之位数组的用法
    如果需要处理的数字有许多位,就可以使用BitArray类和BitVector32结构。BitArray类位于System.Collection,BitVector32结构位于Syst...
    99+
    2024-04-02
  • C#集合之有序列表的用法
    如果需要基于键对所需集合排序,就可以使用SortedList<TKey,TValue>类。这个类按照键给元素排序。这个集合中的值和键都可以使用任何类型。定义为键的自定义类...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作