C#基础提升系列——C#集合
C#集合
有两种主要的集合类型:泛型集合和非泛型集合。 泛型集合被添加在 .NET Framework 2.0 中,并提供编译时类型安全的集合。 因此,泛型集合通常能提供更好的性能。 构造泛型集合时,它们接受类型形参;并在向该集合添加项或从该集合删除项时无需在Object类型间来回转换。
集合接口和类型
- System.Array :用于数组,提供创建,操作,搜索和排序数组的方法,是所有数组的基类。
- System.Collections :是
ArrayList、Queue、Hashtable等基类,包含定义对象的各种集合。 - System.Collections.Concurrent :提供了线程安全的集合类。
- System.Collections.Generic :包含接口和定义泛型集合,它允许用户创建强类型集合能提供比非泛型强类型集合更好的类型安全和性能等级。
- System.Collections.Specialized:包含强类型集合。专用于特定类型的集合类。
- System.Collections.Immutable :包含了定义不可变的集合接口和类 。
列表List<T>
该类派生自如下接口和类:
public class List<T> : System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IList<T>,
System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>,
System.Collections.IList,System.Collections.IEnumerable,System.Collections.ICollection
创建列表
可以调用默认的构造函数创建列表对象。
List<int> intList = new List<int>();
使用构造函数创建一个空列表,当元素添加到列表中后,列表的容量就会扩大为可接纳4个元素,当添加第5个元素时,列表的容量大小就会被重新设置为包含8个元素,如果8个元素还不够 ,列表的容量大小就会被设置为16个元素,每次超出已有的容量大小后,都会将列表的容量重新设置为原来的2倍。
使用Capacity属性可以获取该列表的容量大小。下面将使用一个示例来说明添加元素后,Capacity的值是如何变化的。
List<int> intList = new List<int>();
//获取初始容量大小
Console.WriteLine("初始容量大小:" + intList.Capacity);
intList.Add(1);
Console.WriteLine($"添加了一个元素后,容量大小为:{intList.Capacity}");
//获取或设置该内部数据结构在不调整大小的情况下能够容纳的元素总数
intList.Capacity = 5;
Console.WriteLine("设置了指定的容量大小为5后:" + intList.Capacity);
intList.AddRange(new[] { 2, 3, 4, 5, 6 });
Console.WriteLine($"添加了{intList.Count}个元素后,容量大小为:{intList.Capacity}");
上述的输出结果依次为:
初始容量大小:0
添加了一个元素后,容量大小为:4
设置了指定的容量大小为5后:5
添加了6个元素后,容量大小为:10
>
如果元素添加到列表后,还有多余的容量大小,可以调用TrimExcess()方法,去除不需要的容量。
注意:如果未使用的容量小于总容量的10%,则列表不会调整大小 。
接着上述示例执行下述代码:
Console.WriteLine($"原来的元素个数为:{intList.Count} 容量大小为:" + intList.Capacity);
intList.TrimExcess();
Console.WriteLine("调用了TrimExcess()方法后,容量大小为:" + intList.Capacity);
//重新调整容量大小,未使用容量小于总容量10%
intList.Capacity = 7;
intList.TrimExcess();
Console.WriteLine($"最终元素个数为:{intList.Count} 容量大小为:" + intList.Capacity);
输出结果为:
原来的元素个数为:6 容量大小为:10
调用了TrimExcess()方法后,容量大小为:6
最终元素个数为:6 容量大小为:7
初始化集合并设定值
intList = new List<int>() { 1, 2, 3 };
intList = new List<int> { 4, 5, 6 };
添加或插入元素
使用Add()方法可以给列表添加一个元素,使用AddRange()方法可以一次给集合添加多个元素。使用Insert()方法可以在指定位置插入元素:
intList.Add(7);
intList.AddRange(new int [] { 7, 8, 9 });
intList.Insert(2, 0);
//4 5 0 6 7 7 8 9
访问元素
实现了IList和IList<T>接口的所有类都提供了一个索引器,因此可以使用索引下标的形式进行访问指定索引位置的元素。索引下标从0开始。
> Console.Write(intList[2]);
0
因为List<T>集合类实现了IEnumerate接口,所以可以使用foreach语句进行遍历集合中的元素。
删除元素
使用RemoveAt()方法移除指定索引位置的元素,使用Remove()方法移除指定元素。使用RemoveRange()方法可以从集合中删除多个元素。使用RemoveAll()方法可以删除集合中的所有的元素。
注意:推荐使用RemoveAt()方法按索引删除元素,因为它比Remove()方法执行的要快,Remove()方法会先在集合中搜索元素,搜索的过程中会调用Equals()方法,然后使用IndexOf()方法获取元素的索引,再使用该索引删除元素。
intList.RemoveAt(2);//删除索引2的元素
intList.Remove(7);//删除元素7
intList.RemoveRange(4, 2);//删除索引为4及之后的2个元素
intList.RemoveAll(a => a > 5); //删除值大于5的元素
搜索元素
可以通过索引或元素本身搜索元素。可以使用的方法有:IndexOf()、LastIndexOf()、FindIndex()、FindLastIndex()、Find()、FindLast()等。判断元素是否存在可以使用Exists()方法。除了这些方法,实际应用中还包括Linq可以使用的方法。具体使用,请查看官方文档。
排序
List<T>类可以使用Sort()方法对元素进行排序。Sort()方法有如下几个重载方法:
public void Sort(int index, int count, IComparer<T> comparer);
public void Sort(Comparison<T> comparison);
public void Sort();
public void Sort(IComparer<T> comparer);
只有集合中的元素实现了IComparable接口,才能使用不带参数的Sort()方法。
如果需要按照元素类型 不 默认支持的方式排序,就需要使用其他重载方法,比如传递一个实现了IComparer<T>接口的对象。
下面将用一个具体的示例进行说明:
public class Racer : IComparable<Racer>
{
public int Id { get; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country { get; set; }
public int Wins { get; set; }
//实现接口中的方法
public int CompareTo(Racer other)
{
int compare = LastName?.CompareTo(other?.LastName) ?? -1;
if (compare == 0)
{
return FirstName?.CompareTo(other?.FirstName) ?? -1;
}
return compare;
}
//定义构造函数
public Racer(int id, string firstName, string lastName, string country, int wins)
{
this.Id = id;
this.FirstName = firstName;
this.LastName = lastName;
this.Country = country;
this.Wins = wins;
}
//定义另一个构造函数,并调用上述构造函数
public Racer(int id, string firstName,