鼎鼎知识库
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

5 年前
5 年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. > 字典
  2. - 字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素,字典也称为映射或散列表。
  3. - 字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List<T>类,但没有在内存中移动后续元素的性能开销。
  4. **键的类型**
  5. - 用作字典中的键的类型必须重写Object类的GetHashCode()方法。只要字典类需要确定元素的位置,它就要调用GetHashCode()方法。
  6. - GetHashCode()方法的实现代码必须满足如下要求:
  7. - 相同的对象应总是返回相同的值。
  8. - 不同的对象可以返回相同的值。
  9. - 它不能抛出异常。
  10. - 它应至少使用一个实例字段。
  11. - 散列代码最好在对象的生存期中不发生变化。
  12. - 它应执行的比较快,计算的开销不大
  13. - 散列代码值应平均分布在int可以存储的整个数字范围上。
  14. > 字典示例
  15. - 字典示例程序建立一个员工字典。该字典用EmployeeId对象来索引,储存在字典中的每个数据项都是一个Employee对象,该对象存储员工的详细数据。
  16. ```
  17. public class EmployeeIdException:Exception
  18. {
  19. public EmployeeIdException(string message):base(message){}
  20. }
  21. public truct EmployeeId:IEquatable<EmployeeId>
  22. {
  23. private readonly char _prefix;
  24. private readonly int _number;
  25. public EmployeeId(string id)
  26. {
  27. Contract.Requires<ArgumentNullException>(id!=null);
  28. _prefix=(id.ToUpper())[0];
  29. int numLength=id.Length-1;
  30. try
  31. {
  32. _number=int.Parse(id.Substring(1,numLength>6?6:numLength));
  33. }
  34. catch (FormatException)
  35. {
  36. throw new EmployeeIdException("Invalid EmployeeId format");
  37. }
  38. }
  39. public override string ToString()=>_prefix.ToString()+$"{number,6:000000}";
  40. public override int GetHashCode()=>(number^number<<16)*0x15051505;
  41. public bool Equals(EmployeeId other)=>(prefix==other?.prefix && number == other?.number);
  42. public override bool Equals(object obj)=>Equals((EmployeeId)obj);
  43. public static bool operator ==(EmployeeId left,EmployeeId right)=>left.Equals(right);
  44. public static bool operator !=(EmployeeId left,EmployeeId right)=>!(left==right);
  45. }
  46. ```
  47. - 由IEquatable<T>接口定义的Equals()方法比较两个EmployeeId对象的值,如果这两个值相同,它就返回true。除了实现IEquatable<T>接口中的Equals()方法之外,还可以重写Object类中的Equals()方法。
  48. - Employee类是一个简单的实体类,该实体类包含员工的姓名、薪水和ID。构造函数初始化所有值,ToString()方法返回一个实例的字符串表示。ToString()方法的实现代码使用格式化字符串创建字符串表示,以提高性能
  49. ```
  50. public class Employee
  51. {
  52. private string _name;
  53. private decimal _salary;
  54. private readonly EmployeeId _id;
  55. public Employee (EmployeeId id,string name,decimal salary)
  56. {
  57. _id=id;
  58. _name=name;
  59. _salary=salary;
  60. }
  61. public override string ToString()=>$"{id.ToString()}:{name,-20} {salary:C}";
  62. }
  63. ```
  64. - 示例应用程序的Main()方法中,创建一个新的Dictionary<TKey,TValue>实例,其中键是EmployeeId类型,值是Employee类型。构造函数指定31个元素的容量。注意容量一般是素数。但如果指定了一个不是素数的值,也不需要担心。Dictionary<TKey,Tvalue>类会使用传递给构造函数的整数后面紧接着的一个素数来指定容量。创建员工对象和ID后,就使用新的字典初始化语法把它们添加到新建的字典中
  65. ```
  66. public static void Main()
  67. {
  68. var employees=new Dictionary<EmployeeId,Employee>(31);
  69. var idTony =new EmployeeId("c3755");
  70. var tony =new Employee(idTony,"Tony Stewart",379025.00m);
  71. var idCarl=new EmployeeId("F3547");
  72. var carl=new Employee(idCarl,"Carl Edwards",403466.00m);
  73. var idKevin=new EmployeeId("c3386");
  74. var kevin=new Employee(idKevin,"Kevin Harwick",415261.00m);
  75. var idMatt=new EmployeeID("F3323");
  76. var matt=new Employee(idMatt,"Matt Kenseth",1589390.00m);
  77. var idBrad=new EmployeeId("D3234");
  78. var brad=new Employee(idBrad,"Brad Keselowski",322295.00m);
  79. var employees=new Dictionary<EmployeeId,Employee>(31)
  80. {
  81. [idTony]=tony,
  82. [idCarl]=carl,
  83. [idKevin]=kevin,
  84. [idMatt]=matt,
  85. [idBrad]=brad
  86. };
  87. foreach(var employee inemployee.Values)
  88. {
  89. WriteLine(employee);
  90. }
  91. }
  92. ```
  93. ```
  94. while (true)
  95. {
  96. Write("Enter employee id(X to exit)");
  97. var userInput=ReadLine();
  98. userInput=userInput.ToUpper();
  99. if(userInput == "X") break;
  100. EmployeeId id;
  101. try
  102. {
  103. id=new EmployeeId(userInput);
  104. Employee employee;
  105. if(!employee.TryGetValue(id,out employee))
  106. {
  107. WriteLine($"Employee with id{id} does not exist");
  108. }
  109. else
  110. {
  111. WriteLine(employee);
  112. }
  113. }
  114. catch(EmployeeIdException ex)
  115. {
  116. WriteLine(ex.Message);
  117. }
  118. }
  119. ```
  120. > Lookup类
  121. - Dictionary<TKey,TValue>类支持每个键关联一个值。Lookup<TKey,TElement>类非常类似于Dictionary<TKey,TValue>类,但把键映射到一个值集合上。这个类在程序集System.Core中实现,用System.Linq名称空间定义。
  122. - Lookup<TKey,TElement>类不能像一般的字典那样创建,而必须调用ToLookup()方法,该方法返回一个Lookup<TKey,TElement>对象。ToLookup()方法是一个扩展方法,它用于实现IEnumberable<T>接口的所有类。
  123. - 下面例子中,填充一个Racer对象列表。因为List<T>类实现了IEnumberable<T>接口,所以可以在赛车手列表上调用ToLookup()方法。这个方法需要一个Func<TSource,Tkey>类的委托,Func<TSource,TKey>类定义了键的选择器。
  124. ```
  125. var racers=new List<Racer>();
  126. racers.Add(new Racer("Jacques","Villeneuve","Canada",11));
  127. racers.Add(new Racer("Alan","Jones","Australia",12));
  128. racers.Add(new Racer("Jackie","Stewart","United Kingdom",27));
  129. racers.Add(new Racer("James","Hunt","United Kingdom",10));
  130. racers.Add(new Racer("Jack","Brabham","Australia",14));
  131. var lookupRacers=racers.ToLookup(r=>r.Country);
  132. foreach (Racer r in lookupRacers("Australia"))
  133. {
  134. WriteLine(r);
  135. }
  136. ```
  137. > 有序字典
  138. - SortedDictionary<TKey,TValue>是一个二叉搜索树,其中的元素根据键来排序。该键类型必须实现IComparablc<TKey>接口。如果键的类型不能排序,则还可以创建一个实现了IComparer<TKey>接口的比较器,将比较器用作有序字典的构造函数的一个参数。
  139. - SortedDictionary<TKey,TValue>和SortedList<TKey,TValue>的功能类似。但因为SortedList<TKey,TValue>实现为一个基于数组的列表,而SortedDictionary<TKey,TValue>类实现为一个字典。他们有不同的特征。
  140. - SortedList<TKey,TValue>使用的内存比SortedDictionary<TKey,TValue>少。
  141. - SortedDictionary<TKey,TValue>的元素插入和删除操作比较快。
  142. - 在用已排好序的数据填充集合时,若不需要修改容量,SortedList<TKey,TValue>比较快