System.Collections命名空间包含可使用的集合类和相关的接口。该命名空间下的.NET非泛型集合类如下所示。
— System.Collections.ArrayList:数组集合类
— System.Collections.BitArray:布尔集合类
— System.Collections.Queue:队列
— System.Collections.Stack:堆栈
— System.Collections.Hashtable:哈希表
— System.Collections.SortedList:排序集合类
注意:本章的示例性代码都在using区添加了System.Collections。
ArrayList类可以视作是Array与Collection对象的结合。该类既有数组的特征又有集合的特性,例如,既可以通过下标进行元素访问,对元素排序、搜索,又可以像处理集合一样添加、在指定索引插入及删除元素。
由于ArrayList中元素的类型默认为object类型,因此,在获取集合元素时需要进行强制类型转换。并且object是引用类型,在与值类型进行转换时,会引起装箱和拆箱的操作,需要付出一些性能代价。
为了创建ArrayList,可以使用三种重载构造函数中的一种,还可以使用ArrayList的静态方法Repeat创建一个新的ArrayList。这三个构造函数的声明如下。
//使用默认的初始容量创建ArrayList,该实例并没有任何元素 public ArrayList(); //使用实现了ICollection接口的集合类来初始化新创建的ArrayList public ArrayList(ICollection c); //经由指定一个整数值来初始化ArrayList的容量 public ArrayList(int capacity); //下面的例子代码演示了使用4种创建ArrayList的方法。 static void Main(string[] args) { //使用默认的初始容量创建ArrayList,该实例并没有任何元素 ArrayList al1 = new ArrayList(); al1.Add("111"); al1.Add("222"); al1.Add("333"); DisplayResult(al1); //使用实现了ICollection接口的集合类来初始化新创建的ArrayList,该实例与参数中的集合具有相同的初始容量 ArrayList al2 = new ArrayList(al1); //调用显示结果子程序 DisplayResult(al2); //经由指定一个整数值来初始化ArrayList的容量 ArrayList al3 = new ArrayList(20); DisplayResult(al3); //将指定ccc字符串重复4次构造数组 ArrayList al4=ArrayList.Repeat("ccc", 4); DisplayResult(al4); Console.ReadLine(); } //在控制台窗口显示数组的内容 static void DisplayResult(ArrayList ls) { Console.WriteLine(""); if (ls.Count <= 0) { Console.WriteLine("数组没有任何集合元素"); } foreach (object s in ls) { Console.Write(Convert.ToString(s)); } } //注意:为了实现上面的例子,必须在using区添加System.Collections命名空间。
有两种方法可用于向ArrayList添加元素:Add和AddRange。
— Add方法将单个元素添加到列表的尾部。
— AddRange方法获取一个实现ICollection接口的集合实例,例如Array、Queue、Stack等,并将这个集合实例按顺序添加到列表的尾部。
这两个方法的声明如下。
//参数:value:需要添加到ArrayList中的值 public virtual int Add(object value); //参数:c:实现了ICollection的集合类 public virtual void AddRange(ICollection c); //注意:ArrayList接受null值并且允许元素重复。 //下面代码演示了如何添加集合元素。 static void Main(string[] args) { //声明一个接受20个元素的ArrayList ArrayList al = new ArrayList(20); //使用ArrayList的Add方法添加集合元素 al.Add("我是元素一"); al.Add("我是元素二"); al.Add("我是元素三"); al.Add("我是元素四"); string[] strs ={ "我是元素五", "我是元素六", "我是元素七", "我是元素八" }; //使用AddRange方法添加实现了ICollections接口的集,并按集合参数中元素的顺序添加 al.AddRange(strs); foreach (string str in al) { Console.WriteLine(str); } Console.ReadLine(); }
插入元素也是向集合中增加元素,与添加(Add或AddRange)元素不同的是,插入元素可以指定要插入的位置的索引,而添加只能在集合的尾部顺序添加。插入元素也有两种方法:Insert和InsertRange。
— Insert方法添加单个元素到指定的索引位置。
— InsertRange从指定的位置开始添加一个实现了ICollection接口的实例。
这两个方法的声明如下所示。
//在指定的索引位置index中添加单个元素值value public virtual void Insert(int index, object value); //在指定的索引位置index处添加实现了ICollection接口的集合实例 public virtual void InsertRange(int index, ICollection c); //下面的示例代码演示了插入集合元素的方法。 static void Main(string[] args) { ArrayList al = new ArrayList(20); //使用Insert方法插入集合元素 al.Insert(0, "我是元素一"); al.Insert(1, "我是元素二"); al.Insert(2, "我是元素三"); al.Insert(3, "我是元素四"); Queue qu=new Queue(); qu.Enqueue("我是元素五"); qu.Enqueue("我是元素六"); qu.Enqueue("我是元素七"); //使用InsertRange方法插入集合元素 al.InsertRange(4,qu); foreach(string s in al) { Console.WriteLine(s); } Console.ReadLine(); }
ArrayList提供了三种方法将指定元素从集合中移除,这三种方法是Remove、RemoveAt和RemoveRange方法。
— Remove方法接受一个object类型值的参数,用于移除指定元素值的第一个匹配集合元素。
— RemoveAt方法接受一个int类型的参数,用于删除指定索引的集合元素。
— RemoveRange方法从集合中移除一定范围的元素。
这三个方法的声明如下所示。
//从ArrayList实例中删除与obj值匹配的第一个元素 public virtual void Remove(object obj); //删除指定索引位置index的元素 public virtual void RemoveAt(int index); //从指定索引位置index开始,移除count个元素 public virtual void RemoveRange(int index, int count); //下面示例演示了使用Remove方法。 static void Main(string[] args) { ArrayList al = new ArrayList(20); al.AddRange(new string[8] { "元素一", "元素二", "元素三", "元素四", "元素五","元素六","元素七","元素八" }); //调用Remove方法删除配置元素 al.Remove("元素二"); //调用RemoveAt方法删除指定索引位置元素 al.RemoveAt(2); //调用RemoveRange方法删除指定范围的元素 al.RemoveRange(3, 2); foreach (string s in al) { Console.WriteLine(s); } Console.ReadLine(); }
使用Sort方法,可以对集合中的元素进行排序。Sort有三种重载方法,声明代码如下所示。
//使用集合元素的比较方式进行排序 public virtual void Sort(); //使用自定义比较器进行排序 public virtual void Sort(IComparer comparer); //使用自定义比较器进行指定范围的排序 public virtual void Sort(int index, int count, IComparer comparer) //本节只介绍如何使用第一种方法进行简单的排序,下一节将介绍如何使用自定义的排序规则进行较复杂的排序。 //注意:为使用Sort方法进行排序,集合中的所有元素必须实现IComparable接口,否则,将抛出异常。 //下面的示例演示了如何使用Sort方法进行排序。 static void Main(string[] args) { ArrayList al = new ArrayList(); al.AddRange(new string[8] { "Array1", "Array2", "Array3", "Array5", "Array4", "Array8", "Array7", "Array6" }); al.Sort(); foreach (string s in al) { Console.WriteLine(s); } Console.ReadLine(); }
除了使用集合元素默认的比较器进行排序外,可以传递实现IComparer接口的类,按自定义的排序逻辑进行排序。上一节已经列出过Sort的三种重载方法,本节讲述如何应用后两种方法实现复杂排序。
举一个场景:笔者有很多IT书籍,希望将书籍按着价格从高向低排序,或者将书籍按书名进行排序。下面的代码演示了使用Sort类的重载方法进行复杂排序的方法。
//1.定义Book类 /// <summary> /// 定义书籍类。具有三种属性:书名,分类,价格 /// </summary> public class Book { //定义书名属性 private string _bookname; public string BookName { get { return _bookname; } set { _bookname = value; } } //定义书籍分类属性 private string _bookcategory; public string BookCategory { get { return _bookcategory; } set { _bookcategory = value; } } //定义价格属性 public double _price; public double Price { get { return _price; } set { _price = value; } } //书籍类的构造函数 public Book(string bookname,string bookcategory,double price) { _bookname = bookname; _bookcategory = bookcategory; _price = price; } } //2.实现Icomparer接口的比较器 /// <summary> /// 按价格从高到低排序 /// </summary> public class InstanceCompare:IComparer { #region IComparer<Book> 成员 public int Compare(object x, object y) { //使用书籍类的价格进行比较 double i = ((Book)y).Price - ((Book)x).Price; if (i > 0) return 1; else if (i < 0) return -1; else return 0; } #endregion } /// <summary> /// 按照书名从高到低排序 /// </summary> public class BookNameCompare:IComparer { #region IComparer 成员 public int Compare(object x, object y) { //调用.NET预定义的按指定忽略大小写的比较器比较书名 return new CaseInsensitiveComparer().Compare(((Book)y).BookName, ((Book)x).BookName); } #endregion } //3.调用Sort重载方法进行排序处理 static void Main(string[] args) { //声明并初始化书籍数组 Book[] books = new Book[8]{new Book("C#书籍z","C#",45.5),new Book("C#书籍f","C#",55.8), new Book("Delphi书籍1","Delphi",78),new Book("C#书籍x","C#",55.9),new Book("ASP.NET","ASP.NET",66), new Book("Delphi书籍2","Delphi",79),new Book("C#书籍y","C#",60),new Book("C#书籍b","C#",80)}; ArrayList al = new ArrayList(books); Console.WriteLine("排序前的集合排列"); DispalyResult(al); //对数组按价格进行排序,调用InstanceCompare比较器 al.Sort(new InstanceCompare()); Console.WriteLine("按价格排序后的集合排列"); DispalyResult(al); //对数组按书籍名称进行排序,调用BookNameCompare比较器 al.Sort(new BookNameCompare()); Console.WriteLine("按书名排序后的集合排列"); DispalyResult(al); Console.ReadLine(); } 4.//显示数组内容 static void DispalyResult(ArrayList al) { foreach (Book book in al) { Console.WriteLine("书名:{0} 价格:{1}",book.BookName,book.Price); } }
为了在数组列表中查找元素,最常使用的是IndexOf或LastIndexOf方法,另外,还可以使用BinarySearch方法执行搜索。
— IndexOf方法从前向后搜索指定的字符串,如果找到,返回匹配的第一项的自0开始的索引,否则,返回-1。
— LastIndexOf方法从后向前搜索指定的字符串,如果找到,返回匹配的最后一项的自0开始的索引,否则,返回-1。
这两个方法各自都有三个重载版本,表示从指定的索引处开始搜索或者是从指定索引处搜索指定长度的字符串。
BinarySearch使用二分算法从集合中搜索指定的值,并返回找到的从0开始的索引,否则,返回-1。下面的示例代码将演示如何使用这些方法来查找数组中的元素。
static void Main(string[] args) { string[] str ={ "元素一", "元素二", "元素三", "元素四", "元素五", "元素六" }; ArrayList al = new ArrayList(str); int i = al.IndexOf("元素三"); Console.WriteLine("元素三在集合中的位置是" + i); i = al.LastIndexOf("元素五"); Console.WriteLine("元素五在集合中的位置是" + i); int j = al.BinarySearch("元素三"); if (j >0) Console.WriteLine("元素六在集合中的位置是" + j); else Console.WriteLine("没有找到元素一"); Console.ReadLine(); }
ArrayList内部维护着一个数组,可以通过下标进行访问,而且ArrayList实现了IEnumerable接口,因此,要遍历集合,可以使用for或foreach方法。
下面的代码示例演示了如何使用for和foreach进行集合元素遍历。
static void Main(string[] args) { ArrayList al = new ArrayList(new string[6] { "元素一", "元素二", "元素三", "元素四", "元素五", "元素六" }); //使用for遍历 Console.WriteLine("for"); for (int i = 0; i <= al.Count - 1; i++) { Console.Write(al[i]); } Console.WriteLine(""); Console.WriteLine("foreach"); //使用foreach遍历 foreach (object s in al) { Console.Write(s); } Console.ReadLine(); }