集合
前言:在前面的博客中我们讲到了数组http://www.cnblogs.com/MoRanQianXiao/p/7825013.html。数组的大小是固定的。如果元素的个数是动态的。就应使用集合类。
一:集合接口和类型
List<T>是与数组相当的集合类。还有其他类型的集合:队列、栈、链表、字典和集。其他集合类提供的访问集合元素的API可能稍有不同。他们在内存中存储元素的内部结构也有区别。我们会在本章的博客中进行讲解。
大多数的集合类都能在System.Collections和System.Collections.Generic命名空间中找到。泛型集合类位于System,Collections命名空间中。
二:列表
.NET Framework 为动态列表提供了泛型类List<T>。这个类实现了IList、ICollection、IEnumerable、IList<T>、ICollection<T>和IEnumerable<T>接口。
2.1:创建列表:
调用默认的构造函数,就可以创建列表对象。在泛型类List<T>中,必须声明为列表的值指定类型。下面的代码说明了如何声明一个包含int的List<T>泛型类的列表。ArrayList是一个非泛型列表。它可以将任意Object类型作为其元素。
使用默认的构造函数创建一个空列表。元素添加到列表中。列表的容量就会扩大为可接纳4个元素。如果添加了第5个元素,列表的容量就会重新设置为包含8个元素。如果8个元素还不够。列表的大小就 重新设置为包含16个元素。每次都将会列表的容量重新设置为原来的2倍。
如果列表的容量变了,那么整个集合就会被重新分配到一个新的内存块中,在List<T>泛型类的实现代码中,使用了一个T类型的数组。通过重新分配内存,创建一个新数组。Array.Copy()方法将旧数组中的元素复制到新数组中。为节省时间,如果事先先知道列表中元素的个数,就可以用构造函数定义其容量。下面创建了一个容量为10个元素的集合。如果该容量不足以容纳要添加的元素。就把集合的大小重新设置为包含20或者40个元素。每次都是原来的2倍。
static void Main(string[] args) { List<int> intList = new List<int>(5); //集合中的容量 Console.WriteLine(intList.Capacity); //集合中的个数 Console.WriteLine(intList.Count); Console.ReadKey(); }
容量与集合的元素的个数不同。集合中的元素的个数可以用Count属性来读取。当然,容量总是大于等于元素的个数。只要不把元素添加到列表中,元素个数就是0.
如果已经将元素添加到列表中,且不希望添加更多的元素,就可以调用TrimExcess()方法。去除不需要的容量。但是因为重新定位需要时间。所以如果元素的个数超过了容量的90%,TrimExcess()就什么也不做。
2.2:集合初始化设定项:
还可以使用集合初始化项给集合赋值。集合初始化项与在介绍数组初始化项类似。使用集合初始化项设定项,可以在初始化集合时,在花括号中给集合赋值:
var intList = new List<int>() { 1, 2 }; var stringList = new List<string>() { "张三", "李四" };
2.3:添加元素:
使用Add()方法可以给列表添加元素。 实例化泛型类型定义了Add()方法的参数类型:
var intList = new List<int>(); var stringList = new List<string>(); intList.Add(1); intList.Add(2); stringList.Add("张三"); stringList.Add("李四");
2.4:插入元素:
使用Insert()方法可以在指定的位置插入元素。
static void Main(string[] args) { var intLists = new List<int>(); var stringList = new List<string>(); intLists.Add(1); intLists.Add(2); //1:表示索引的位置 5:表示要插入的元素 intLists.Insert(1, 5); stringList.Add("张三"); stringList.Add("李四"); foreach (var intList in intLists) { Console.WriteLine(intList); } Console.ReadKey(); }
2.5:访问元素:
实现了IList 和IList<T>接口的所有类都提供了一个索引器,所以可以使用索引器,通过传送元素号来访问元素。第一个元素可以用索引值0来进行访问。
int num = intLists[0];
可以用Count属性来确定元素的个数,在使用for循环遍历集合中的每个元素。并使用索引器访问每一项:
for (int i = 0; i < intLists.Count; i++) { Console.WriteLine(intLists[i]); }
因为List><T>集合实现了IEnumberable接口。所以也可以使用foreach语句来遍历集合中的每个元素。
foreach (var intList in intLists) { Console.WriteLine(intList); }
2.6:删除元素:
删除元素时,可以利用索引,也可以传递要删除的元素,Insert()方法。
//删除第一个元素(按索引进行删除) intLists.RemoveAt(0);
RemoveRange()方法可以从集合中删除许多的元素。第一个参数指定了开始删除的元素的索引。第二个参数指定了要删除的元素的个数。下面的代码指的是第一个元素开始删除,删除两个元素。
intLists.RemoveRange(0, 1);
要删除集合中的所有的元素,可以使用ICollection<T>接口定义的Clear()方法。
intLists.Clear();
2.7:搜索:
有不同的方式在集合中搜索元素。可以获得要查找的元素的索引。或者搜索元素本身。可以使用的方法有IndexOf()、LastIndexOf()、FindIndex()、FindLastIndex()、Find()和FindLast()。如果只检查元素是否存在。List<T>类提供了Exists()方法。
IndexOf()方法需要将一个对象作为参数,如果集合中找到该元素。这个方法就返回该元素的索引。如果没有找到该元素。就返回-1。
int res = intLists.IndexOf(1); //返回0
除了使用IndexOf()方法来搜索指定的元素之外,还可以搜索有某个特性的元素。给特性可以用FindIndex()方法来定义。FindIndex()方法需要一个Predicate类型的参数:
public delegate bool Predicate<T>(T obj);
Predicate<T>是一个委托,该委托返回一个布尔值,并且需要把类型T作为参数。这个委托用法与Action()委托类似。如果Predicate<T>委托返回一个true,就表示有一个匹配元素。并且找到了相应的元素。如果他返回false,就表示他没有找到元素。搜索将继续。
FindIndex()方法:里面的参数是一个委托的类型(该方法的类型是定义了一个参数且返回一个布尔值)。如不清楚Lambda表达式请查看链接:http://www.cnblogs.com/MoRanQianXiao/p/7772234.html
int res = intLists.FindIndex(i => i == 1);
LastIndexOf()方法 搜索指定的对象,并返回整个List<T>中最后一个匹配项的从零开始的索引(1 5 2 3 4)。
int res = intLists.LastIndexOf(2); //2
FindLastIndex()方法 搜索与指定谓词所定义的条件相匹配的元素,并返回整个List<T> 中最后一个匹配元素的从零开始的索引(1 5 2 3 4)。
int res = intLists.FindLastIndex(i => i == 1); //0
Find()方法 搜索与指定谓词所定义的条件想匹配的元素,并返回整个List<T>中的第一个匹配元素(1 5 2 3 4)。
int res = intLists.Find(i => i == 2); //2
FindLast()方法 搜索与指定的谓词所定义的条件相匹配的元素,并返回整个List<T>中的最后一个匹配的元素。
int res = intLists.FindLast(i => i == 1);
Exists()方法: 确定List<T>是否包含与指定谓词所定义的条件想匹配的元素:
bool res = intLists.Exists(i => i == 1); //true
2.8:排序:
List<T>类可以使用Sort()方法对元素排序。Sort()方法使用快速排序算法。比较所有的元素。知道整个列表排好为止。
intLists.Sort();
还可以使用重载方法:
intLists.Sort((i, i1) => i.CompareTo(i1));