C#集合之列表的用法
.NET Framework為動(dòng)態(tài)列表List提供泛型類List<T>。這個(gè)類實(shí)現(xiàn)了IList,ICollection,IEnumerable,IList<T>,ICollection<T>,IEnumerable<T>接口。
1.創(chuàng)建列表
創(chuàng)建一個(gè)賽車手類,下面的例子會(huì)用到:
public class Racer : IComparable<Racer>, IFormattable { public int Id { get; private set; } public string FirstName { get; set; } public string LastName { get; set; } public string Country { get; set; } public int Wins { get; set; } public Racer(int id, string firstName, string lastName, string country) : this(id, firstName, lastName, country, wins: 0) { } 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 override string ToString() { return String.Format("{0} {1}", FirstName, LastName); } public string ToString(string format, IFormatProvider formatProvider) { if (format == null) format = "N"; switch (format.ToUpper()) { case null: case "N": // name return ToString(); case "F": // first name return FirstName; case "L": // last name return LastName; case "W": // Wins return String.Format("{0}, Wins: {1}", ToString(), Wins); case "C": // Country return String.Format("{0}, Country: {1}", ToString(), Country); case "A": // All return String.Format("{0}, {1} Wins: {2}", ToString(), Country, Wins); default: throw new FormatException(String.Format(formatProvider, "Format {0} is not supported", format)); } } public string ToString(string format) { return ToString(format, null); } public int CompareTo(Racer other) { if (other == null) return -1; int compare = string.Compare(this.LastName, other.LastName); if (compare == 0) return string.Compare(this.FirstName, other.FirstName); return compare; } }
調(diào)用默認(rèn)的構(gòu)造函數(shù),就可以創(chuàng)建列表對(duì)象。在List<T>中,必須為聲明為列表的值指定類型:
var intList = new List<int>(); var racers =new List<Racer>();
使用默認(rèn)的構(gòu)造函數(shù)創(chuàng)建一個(gè)空列表。元素添加到列表中后,列表的容量就會(huì)擴(kuò)大為可接納4個(gè)元素。如果添加到第五個(gè)元素,列表的大小就會(huì)重新設(shè)置為包含8個(gè)元素。如果8個(gè)元素還不夠,列表的大小就會(huì)重新設(shè)置為包含16個(gè)元素。每次都會(huì)將列表容量重新設(shè)置為原來(lái)的2倍。
如果列表的容量改變了,整個(gè)集合就會(huì)重新分配到一個(gè)新的內(nèi)存塊中。在List<T>泛型類的實(shí)現(xiàn)代碼中,使用了一個(gè)T類型的數(shù)組。通過(guò)重新分配內(nèi)存,創(chuàng)建一個(gè)新數(shù)組,Array.Copy()方法將舊數(shù)組中的元素復(fù)制到新數(shù)組中。為節(jié)省時(shí)間,如果事先知道列表中的元素個(gè)數(shù),就可以用構(gòu)造函數(shù)定義其容量:
List<int> intList = new List<int>(10);
使用Capacity屬性可以獲取和設(shè)置集合的容量:
intList.Capacity = 20;
集合的元素個(gè)數(shù)用Count屬性讀取。
如果已經(jīng)將元素添加到列表中,且不希望添加的更多的元素,就可以調(diào)用TrimExcess()方法,去除不需要的容量。但是,因?yàn)橹匦露ㄎ恍枰獣r(shí)間,所以如果元素的個(gè)數(shù)超過(guò)了容量的90%,該方法就什么也不做。
intList.TrimExcess();
還可以使用集合初始值給集合賦值:
var intList = new List<int>(){1,2};
集合初始值并沒(méi)有反映在已編譯的程序集的IL代碼中,編譯器會(huì)把集合初始值變成對(duì)初始值列表中的每一項(xiàng)調(diào)用Add()方法。
2.添加元素
使用Add()方法可以給列表添加元素:
intList.Add(1); intList.Add(2);
使用AddRange()方法,可以一次給集合添加多個(gè)元素。因?yàn)锳ddRange()方法的參數(shù)是IEnumerable<T>類型的對(duì)象,所以可以傳遞一個(gè)數(shù)組:
intList.AddRange( new Int[]{1,2} );
如果在實(shí)例化列表時(shí)知道集合的元素個(gè)數(shù),就亦可以將實(shí)現(xiàn)IEnumerable<T>類型的對(duì)象傳遞給類的構(gòu)造函數(shù),類似AddRange()方法:
var intList = new List<int>( new Int[]{1,2} );
3.插入元素
使用Insert()方法可以在指定位置插入元素:
intList.Insert(3,4);
方法InsertRange()可以插入大量的元素。
racers.InsertRange(3, new Racer[] { new Racer(12, "Jochen", "Rindt", "Austria", 6), new Racer(22, "Ayrton", "Senna", "Brazil", 41) });
4.訪問(wèn)元素
實(shí)現(xiàn)了IList和IList<T>接口的所有類都提供了一個(gè)索引器,可以使用索引器來(lái)訪問(wèn)元素:
int i = intList[0;]
String類也可以通過(guò)索引訪問(wèn)字符:
string s = "sdas"; char c = s[0];
因?yàn)長(zhǎng)ist<T>集合類實(shí)現(xiàn)了IEnumerable接口,所以也可以使用foreach(http://www.dbjr.com.cn/article/244045.htm)語(yǔ)句遍歷集合中的元素:
foreach(int i in intList) { //.. }
除了使用foreach語(yǔ)句之外,List<T>類還提供了ForEach()方法,該方法用Action<T>參數(shù)聲明:
public void ForEach(Action<T> action);
.NEt實(shí)現(xiàn)ForEach()方法的代碼如下:
public class List<T>:ILIst<T> { private T[] items; //... public void ForEach(Action<T> action) { if(action==null) throw new ArgumentNullException("action"); foreach(T item in items) { action(item); } } }
實(shí)例:
racers.ForEach( r => { Console.WriteLine(r.ToString()) } );
這里使用了lambda表達(dá)式(http://www.dbjr.com.cn/article/244054.htm)。
5.刪除元素
刪除元素時(shí),可以利用索引,也可以傳遞要?jiǎng)h除的元素:
var graham = new Racer(7, "Graham", "Hill", "UK", 14); var emerson = new Racer(13, "Emerson", "Fittipaldi", "Brazil", 14); var mario = new Racer(16, "Mario", "Andretti", "USA", 12); var racers = new List<Racer>(20) { graham, emerson, mario }; racers.RemoveAt(3); racers.Remove(graham);
按索引刪除比較快,因?yàn)楸仨氃诩现兴阉饕獎(jiǎng)h除的元素。Remove方法先在集合中搜索,用IndexOf方法獲取元素的索引,再使用該索引刪除元素。IndexOf方法先檢查元素類型是否實(shí)現(xiàn)了IEquatable<T>接口。如果是,就調(diào)用這個(gè)接口的Equals()方法,確定集合中的元素是否等于傳遞給Equals()方法的元素。如果沒(méi)有實(shí)現(xiàn)這個(gè)接口,就使用Object類的Equals()方法比較這些元素。Object類的Equals()方法默認(rèn)實(shí)現(xiàn)代碼對(duì)值類型進(jìn)行按位比較,對(duì)引用類型只比較其引用。
RemoveRange()方法可以從集合中刪除許多元素。它的第一個(gè)參數(shù)指定了開(kāi)始刪除的元素索引,第二個(gè)參數(shù)指定了要?jiǎng)h除的元素個(gè)數(shù):
int index = 3; int count = 5; racers.RemoveRange(index,count);
要?jiǎng)h除集合中的所有元素,可以使用ICollection<T>接口定義的Clear()方法:
racers.Clear();
RemoveAll()方法刪除有指定特性的所以元素。這個(gè)方法使用Predicate<T>類型的參數(shù)定義。下面將介紹Predicate<T>類型。
6.搜索
獲得要查找的元素的索引,或者搜索元素的本身??梢允褂玫姆椒ㄓ蠭ndexOf(),LastIndexOf(),FindIndex(),FindLastIndex(),Find(),FindLast().
如果只檢查元素是否存在,可以使用Exists()方法。
IndexOf()方法需要將一個(gè)對(duì)象作為參數(shù),如果在集合中找到該元素,這個(gè)方法就返回該元素的索引。如果沒(méi)有找到就返回—1.IndexOf方法使用IEquatable<T>接口來(lái)比較元素。
使用IndexOf()方法,還可以指定不需要搜索整個(gè)集合,指定從哪個(gè)元素開(kāi)始搜索以及搜索幾個(gè)元素。
除了使用IndexOf()方法搜索指定元素之外,還可以搜索有某個(gè)特性的元素,該特性可以用FindIndex(),FindLastIndex(),Find(),FindLast()方法來(lái)定義,這些方法需要一個(gè)Predicate<T>類型的參數(shù):
如:
public int FindIndex(Predicate<T> match);
Predicate<T>類型是一個(gè)委托:
public delegate bool Predicate<T>(T obj);
其用法和Foreach()方法的Action委托類似。如果Predicate<T>委托返回true,就表示有一個(gè)匹配元素。如果返回false,表示沒(méi)找到,繼續(xù)搜素。
FindIndex(),FindLastIndex()方法返回找到的匹配元素的一個(gè)索引;Find(),FindLast()返回這個(gè)匹配的元素。
如果要獲得與Predicate<T>匹配的所有項(xiàng)而不是一項(xiàng),可以使用FindAll()方法。FindAll()方法的用法一樣。FindAll()方法找到第一項(xiàng)后不會(huì)停止,而是繼續(xù)迭代集合中的每一項(xiàng):
List<Racer> l = racers.FindAll(r => r.Wins > 20);
7.排序
List<T>類可以使用Sort()方法對(duì)集合中的元素排序。Sort()方法使用快排算法排序。
Sort()方法有多個(gè)重載的方法??梢詡鬟f泛型委托Comparison<T>和泛型接口IComparer<T>,以及一個(gè)范圍值和泛型接口IComparer<T>:
public void List<T>.Sort(); public void List<T>.Sort(Comparison<T>); public void List<T>.Sort(IComparer<T>); public void List<T>.Sort(Int32,Int32,IComparer<T>);
只有集合中的元素實(shí)現(xiàn)了IComparable接口,才能使用不帶參數(shù)的Sort()方法。
使用public void List<T>.Sort(IComparer<T>); 需要定義一個(gè)實(shí)現(xiàn)了IComparer<T>接口的類,調(diào)用Sort(IComparer<T>)方法時(shí)會(huì)調(diào)用實(shí)現(xiàn)了IComparer<T>接口的類中的Compare方法:
public class RacerComparer : IComparer<Racer> { public enum CompareType { FirstName, LastName, Country, Wins } private CompareType compareType; public RacerComparer(CompareType compareType) { this.compareType = compareType; } public int Compare(Racer x, Racer y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; int result; switch (compareType) { case CompareType.FirstName: return string.Compare(x.FirstName, y.FirstName); case CompareType.LastName: return string.Compare(x.LastName, y.LastName); case CompareType.Country: result = string.Compare(x.Country, y.Country); if (result == 0) return string.Compare(x.LastName, y.LastName); else return result; case CompareType.Wins: return x.Wins.CompareTo(y.Wins); default: throw new ArgumentException("Invalid Compare Type"); } } }
客戶端代碼:
racers.Sort(new RacerComparer(RacerComparer.CompareType.Country));
使用public void List<T>.Sort(Comparison<T>); 需要一個(gè)Comparison<T>委托。Comparison<T>委托:public delagate int Comparsion<T>(int x,int y);
客戶端代碼:
racers.Sort((r1,r2) => r2.Wins.CompareTo(r1.Wins));
使用Reverse()方法,可以逆轉(zhuǎn)整個(gè)集合的順序。
8.類型轉(zhuǎn)換
使用List<T>類的ConvertAll<TOutput>()方法,可以把所以類型的集合轉(zhuǎn)換位另一種類型。ConvertAll<TOutput>()方法使用Converte委托,Converte委托:public sealed delegate TOutput Converter<TInput,TOutput>(TInput from);
//定義一個(gè)Person類 public class Person { private string name; public Person(string name) { this.name = name; } public override string ToString() { return name; } }
客戶端代碼:
List<Person> persons = racers.ConvertAll<Person>( r => new Person(r.FiastName+" " + r.LastName) );
9.只讀集合
創(chuàng)建集合后,它們就是可讀寫(xiě)的。但是,在填充集合后,可以使用AsReadOnly()方法創(chuàng)建只讀集合。
List<Racer> racers2 =racers.AsReadOnly();
到此這篇關(guān)于C#集合之列表的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
簡(jiǎn)述C#枚舉高級(jí)戰(zhàn)術(shù)
這篇文章主要介紹了簡(jiǎn)述C#枚舉高級(jí)戰(zhàn)術(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10C#中比較常用的DateTime結(jié)構(gòu)的使用方法
這篇文章主要介紹了C#中比較常用的DateTime結(jié)構(gòu)的使用方法,需要的朋友可以參考下2015-11-11C#實(shí)現(xiàn)窗體淡入淡出效果的方法總結(jié)
C#實(shí)現(xiàn)窗體淡入淡出效果的方法總結(jié),需要的朋友可以參考一下2013-05-05C#提示:“在證書(shū)存儲(chǔ)區(qū)中找不到清單簽名證書(shū)”的解決方法
這篇文章主要介紹了C#提示:“在證書(shū)存儲(chǔ)區(qū)中找不到清單簽名證書(shū)”的解決方法,分析了幾種常見(jiàn)的解決方案供大家選擇使用,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01C#實(shí)現(xiàn)只運(yùn)行單個(gè)實(shí)例應(yīng)用程序的方法(使用VB.Net的IsSingleInstance)
這篇文章主要介紹了C#實(shí)現(xiàn)只運(yùn)行單個(gè)實(shí)例應(yīng)用程序的方法,本文使用的是VB.Net的IsSingleInstance方法實(shí)現(xiàn),優(yōu)于Mutex 和 Process 這兩種只運(yùn)行單個(gè)應(yīng)用程序?qū)嵗姆椒?需要的朋友可以參考下2014-07-07