C#中的List
C#中deList怎么樣?List<T>類是ArrayList類的泛型等效類,該類使用大小可按需動(dòng)態(tài)增長(zhǎng)的數(shù)組實(shí)現(xiàn)List<T>泛型接口.
?
泛型的優(yōu)點(diǎn):它為使用C#語(yǔ)言編寫(xiě)面向?qū)ο蟪绦蛱砑恿藰O大的效力和靈活性,不會(huì)強(qiáng)行對(duì)值類型進(jìn)行裝箱和拆箱,或?qū)σ妙愋瓦M(jìn)行向下強(qiáng)制類型轉(zhuǎn)化,所以性能得到提高.
?
性能注意事項(xiàng):再?zèng)Q定使用List<T>還是使用ArrayList類(兩者具有類似的功能)時(shí),記住IList<T>類在大多數(shù)情況下運(yùn)行得更好而且是類型安全的.假設(shè)對(duì)IList<T>類的類型T使用引用類型,則兩個(gè)類的行為是全然同樣的,可是假設(shè)對(duì)類型T使用值類型,則須要考慮實(shí)現(xiàn)和裝箱問(wèn)題.
?
C#List的基礎(chǔ)經(jīng)常用法:
一.聲明:
1.? List<T>?list=new?List<T>():
T為列表中元素類型,如今以string類型作為樣例:
List<string>?list=new?List<string>():
?
2.List<T>?list?=?new?List<T>(IEnumerable<T>?collection);
以一個(gè)集合作為參數(shù)創(chuàng)建List:
????????????string[]?temArr?=?{?"Ha",?"Hunter",?"Tom",?"Lily",?"Jay",?"Jim",?"Kuku",?"Locu"?};
????????????List<string>?testList?=?new?List<string>(temArr);
?
二.加入元素:
1.?List.Add(?Titem)加入一個(gè)元素
比如:testList.Add(“hahaha”);
2.?List.AddRange(IEnumerable?<T>?collection)??加入一組元素
例:????????????string[]?temArr?=?{?"Ha",?"Hunter",?"Tom",?"Lily",?"Jay",?"Jim",?"Kuku",?"Locu"?};
????????????List<string>?testList?=?new?List<string>();
????????????testList.AddRange(temArr);
3.? Insert(int?index?,T?item)?;?在index位置加入一個(gè)元素
例:testList.Insert(1,”hello”);
?
三.遍歷List中的元素:
案例:
????????????string[]?temArr?=?{?"Ha",?"Hunter",?"Tom",?"Lily",?"Jay",?"Jim",?"Kuku",?"Locu"?};
????????????List<string>?testList?=?new?List<string>();
????????????testList.AddRange(temArr);
????????????foreach?(var?item?in?testList)
????????????{
????????????????Console.WriteLine(item);
????????????}
?
四.刪除元素:
1.List.Remove(T?item)刪除一個(gè)值
例:mList.Remove(“hahaha”);
2.List.RemoveAt(int?index);刪除下標(biāo)為index?的元素
例:mList.RemoveAt(0);
3.List.RemoveRange(int?index?,?int?count);從下標(biāo)index開(kāi)始,刪除count個(gè)元素
例:mList.RemoveRange(3,2);
?
五.推斷某個(gè)元素是否在該List中:
List.Contains(T?item)?返回true或false,非常有用
例:????????????string[]?temArr?=?{?"Ha",?"Hunter",?"Tom",?"Lily",?"Jay",?"Jim",?"Kuku",?"Locu"?};
????????????List<string>?testList?=?new?List<string>();
????????????testList.AddRange(temArr);
????????????if?(testList.Contains("Hunter"))
????????????{
????????????????Console.WriteLine("There?is?Hunter?in?the?list");
????????????}
????????????else
????????????{
????????????????testList.Add("Hunter");
????????????????Console.WriteLine("Add?Hunter?successfully.");
????????????}
?
?
?
六.給List里面的元素排序:
List.Sort();
例:mList.Sort();
?
七.給List里面元素順序反轉(zhuǎn):
List.?Reverse?()能夠不List.?Sort?()配合使用,達(dá)到想要的效果
例:
mList.Sort();
?
八、List清空:
List.?Clear?()
例:
mList.Clear();
?
九、獲得List中元素?cái)?shù)目:
List.?Count?()返回int值
例:
in?tcount?=?mList.Count();
Console.WriteLine("The?num?of?elements?in?the?list:?"+count);
?
?
綜合案例:
using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.Threading.Tasks;
?
namespace?集合
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????//比較List<T>(泛型的)和ArrayList(非泛型的)
????????????People?p1?=?new?People("zhangsan",?21);
????????????People?p2?=?new?People("lisi",?11);
????????????People?p3?=?new?People("wangwu",?41);
????????????//將People對(duì)象加到集合中
????????????List<People>?list?=?new?List<People>(4);
????????????list.Add(p1);
????????????list.Add(p2);
????????????list.Add(p3);
????????????/*假設(shè)不指定list容量大小,默認(rèn)是0,僅僅要有元素增加時(shí),會(huì)自己主動(dòng)擴(kuò)展到4,假設(shè)第五個(gè)元素增加時(shí)
?????????????*?就變成了8,第九個(gè)元素增加時(shí),就變成了16
?????????????*?能夠看出,容量總是成倍的增長(zhǎng),擴(kuò)展時(shí)要又一次開(kāi)辟內(nèi)存,這樣會(huì)影響效率,假設(shè)事先知道元素個(gè)數(shù),
?????????????*?或者可能推斷個(gè)數(shù),最好給出個(gè)大體的容量值
?????????????*?我們?cè)黾恿巳齻€(gè)元素,就設(shè)容量大小為4.注意:設(shè)為4不是說(shuō)僅僅能存放四個(gè)元素
?????????????*?而是說(shuō),假設(shè)超出四個(gè),一樣會(huì)成倍擴(kuò)展,這樣做是為了減小擴(kuò)展帶來(lái)的開(kāi)銷?????????????
?????????????*/
?
?
????????????/*
?????????????*?這種方法作用是清楚多于的沒(méi)實(shí)用的內(nèi)存空間.比如:假設(shè)開(kāi)辟大小為100
?????????????*?可是我們僅僅用了4個(gè),其余的不用,是不是浪費(fèi)
?????????????*?本方法調(diào)用時(shí)會(huì)檢查元素個(gè)數(shù)是不是占到了容量的90%以上
?????????????*?假設(shè)是,則不進(jìn)行回收
?????????????*/
????????????list.TrimExcess();
?
?
????????????/*ArrayList方法和List<T>使用方法一樣,不同的是,它是對(duì)象集合
?????????????*?參數(shù)是object這樣會(huì)有裝箱拆箱的可能
?????????????*?所以盡量使用List<>???????????
?????????????*/
?
?
????????????/*
?????????????*?1.初始化集合器
?????????????*?C#3.0開(kāi)始,提供了初始化功能,可是并沒(méi)有反映到IList代碼中
?????????????*?在IList中,一樣也是把它轉(zhuǎn)化成Add方法調(diào)用??????????????
?????????????*/
?
????????????List<int>?l2?=?new?List<int>()?{?1,?2,?3,?4,?5?};
?
????????????/*
?????????????*?2.加入元素AddRange()方法能夠一次性加入一批對(duì)象?????????????
?????????????*/
????????????List<People>?lists?=?new?List<People>(10);
????????????//參數(shù)是一個(gè)必須可能迭代的對(duì)象,也可能是一個(gè)數(shù)組
????????????list.AddRange(new?People[]?{?new?People("aladdin",?20),?new?People("zhao",?6)?});
?
?
????????????//構(gòu)造傳入批量參數(shù),與AddRange效果一樣
????????????List<People>?myList?=?new?List<People>(new?People[]?{?new?People("aladdin",?20),?new?People("zhao",?6)?});
?
?
????????????/*
?????????????*?3.插入元素
?????????????*?使用Insert()方法,能夠在指定位置插入元素
?????????????*?例?我們?cè)?的位置插入,則最后變成了aladdin?jacky?zhao..插入意思就是,這個(gè)位我占了,
?????????????*?曾經(jīng)占這位的和他之后的,通通往后移一位
?????????????*/
????????????myList.Insert(1,?new?People("Jacky",?22));
?
????????????foreach?(var?p?in?myList)
????????????{
????????????????Console.WriteLine(p.name);
????????????}
?
????????????/*
?????????????*4.訪問(wèn)元素
?????????????*ArrayList和List<T>都是提供了索引器來(lái)訪問(wèn)的
?????????????*/
????????????Console.WriteLine("*********訪問(wèn)元素********");
?
????????????for?(int?i?=?0;?i?<?myList.Count;?i++)
????????????{
????????????????Console.WriteLine(myList[i].name);
????????????}
????????????//還能夠使用foreach迭代器來(lái)實(shí)現(xiàn)
????????????/*
?????????????*?public?delegate?void?Action<T>(T?obj);用托付作為參數(shù)
?????????????*/
????????????Console.WriteLine("********用foreach方法輸出********");
????????????myList.ForEach(param?=>?Console.WriteLine(param.name));
?
????????????/*
?????????????*?5.刪除元素
?????????????*?刪除元素能夠使用RemoveAt()直接傳入索引器值
?????????????*?將第一個(gè)元素直接刪除
?????????????*/
????????????myList.RemoveAt(0);
????????????List<People>?lists2?=?new?List<People>(10);
?
????????????People?per1?=?new?People("aladdin",?100);
????????????People?per2?=?new?People("zhao",?100);
????????????People?per3?=?new?People("jacky",?100);
?
????????????lists2.Add(per1);
????????????lists2.Add(per2);
????????????lists2.Add(per3);
?
????????????lists2.Remove(per3);
?
????????????Console.WriteLine("***********刪除后的元素*********");
?
????????????foreach?(var?per?in?lists2)
????????????{
????????????????Console.WriteLine(per.name);
????????????}
?
????????????/*
?????????????*?從結(jié)果能夠看出,名稱為jacky的元素被刪除了
?????????????*?以下說(shuō)一下Remove方法的刪除過(guò)程
?????????????*?用IndexOf方法確定出對(duì)象的索引,然后按索引刪除
?????????????*?在IndexOf方法內(nèi),首先檢查元素是不是實(shí)現(xiàn)了IEquatable接口,假設(shè)是,就調(diào)用這個(gè)
?????????????*?這個(gè)接口的Equals()方法
?????????????*?假設(shè)沒(méi)有實(shí)現(xiàn),則掉用Object中的Equals方法比較元素(也就是地址比較)
?????????????*?以上我們刪除per3,非常明顯是一個(gè)地址,所以被刪除了
?????????????*?以下我們改裝People,實(shí)現(xiàn)了IEquatable<People,在
?????????????*?比較方法中,始終返回false,同per3會(huì)比較失敗,不會(huì)被刪除
?????????????*?結(jié)果三個(gè)都在
?????????????*?假設(shè)要?jiǎng)h除對(duì)象,最好使用索引直接刪除,由于Remove方法經(jīng)歷了一系列過(guò)程后,最后才按索引刪除!
?????????????*?
?????????????*?RemoveRange()方法刪除一個(gè)范圍
?????????????*?第一個(gè)參數(shù):開(kāi)始位置;第二個(gè)參數(shù):個(gè)數(shù)
?????????????*?lists2.RemoveRange(1,2);
?????????????*?使用foreach查看批量刪除后的結(jié)果
?????????????*?foreach?(var?per?in?lists2)
?????????????*{
?????????????*???Console.WriteLine(per.name);
?????????????*}
?????????????*?
?????????????*/
?
?
????????????/*
?????????????*?6.搜索
?????????????*?搜索有非常多方式,能夠使用
?????????????*?IndexOf,LastIndexOf,FindIndex,FindLastIndex,Find,FindLast
?????????????*?假設(shè)指示查看元素的存在情況,能夠使用Exists()方法
?????????????*?IndexOf()方法須要將一個(gè)對(duì)象做參數(shù),假設(shè)存在,就返回本元素在集合中的索引,
?????????????*?假設(shè)找不到就返回-1,IndexOf還能夠使用IEquatable接口來(lái)比較元素???????????????????????????????????????
?????????????*/
????????????List<People>?ls3?=?new?List<People>(10);
?
????????????People?person1?=?new?People("aladdin",100);
????????????People?person2?=?new?People("zhao",100);
????????????People?person3?=?new?People("jacky",100);
?
????????????ls3.Add(person1);
????????????ls3.Add(person2);
????????????ls3.Add(person3);
?
????????????//為了使用默認(rèn)的地址比較,我們把People的接口臨時(shí)去掉
????????????int?index?=?ls3.IndexOf(person3);
????????????Console.WriteLine("per3的索引?:?"+index);
????????????//還能夠指定搜索范圍?從第三個(gè)開(kāi)始,范圍長(zhǎng)度為1
????????????int?index2?=?ls3.IndexOf(person3,?2,?1);
????????????Console.WriteLine(index2);
????????????//FindIndex()方法用來(lái)搜索帶有一定特性的元素
????????????//用托付做參數(shù)?public?delegate?bool?Predicate<T>(T?obj);
????????????int?index3?=?ls3.FindIndex(param?=>?param.name.Equals(""));
?
????????????Console.WriteLine(index3);//2
????????????//FindLastIndex是從?后面查第一個(gè)出現(xiàn)的元素,由于我們這里沒(méi)有反復(fù)元素,所以
????????????//體現(xiàn)不出它僅僅能查找一個(gè),就停下來(lái)的效果
????????????int?index4?=?ls3.FindLastIndex(p?=>?p.name.Equals("aladdin"));
????????????Console.WriteLine(index4);
?
????????????//Find方法與FindIndex方法用于一樣,不同的是,它返回的是元素本身
????????????People?ppp?=?ls3.Find(p?=>?p.name.Equals("jacky"));
????????????Console.WriteLine(ppp);
?
????????????/*
?????????????*?假設(shè)要查找全部的匹配元素,而不是找到第一個(gè)就停下來(lái),就是用FindAll()方法
?????????????*?我們查找全部年紀(jì)等于100的對(duì)象,3個(gè)都符合
?????????????*/
????????????List<People>?newList?=?ls3.FindAll(p?=>?p.age?==?100);
?
????????????Console.WriteLine("**********查找全部**********");
?
????????????foreach?(var?p?in?newList)
????????????{
????????????????Console.WriteLine(p.name);
????????????}
?
????????????/*
?????????????*?7.排序
?????????????*?List能夠利用Sort方法排序,實(shí)現(xiàn)算符是高速排序
?????????????*?本方法有好幾個(gè)重載
?????????????*?public?void?Sort()僅僅對(duì)元素實(shí)現(xiàn)了IComparable才干使用這種方法?,假設(shè)實(shí)現(xiàn)了則,能夠直接調(diào)用一次sort之后,就排好序了
?????????????*?public?void?Sort(Comparison<T>?comparison)我們的Person并沒(méi)有實(shí)現(xiàn)那個(gè)接口,所以要用泛型托付當(dāng)參數(shù)的方法
?????????????*?public?void?Sort(IComparer<T>(T?x?,?T?y))泛型接口當(dāng)參數(shù)?public?delegate?int?Comparison<T>(T?x,?T?y);
?????????????*?
?????????????*?public?void?Sort(int?index?,int?count?,IComparer<T>?comparer)?能夠指定范圍
?????????????*/
????????????List<People>?ls4?=?new?List<People>(10);
?
????????????People?person4?=?new?People("aladdin",100);
????????????People?person5?=?new?People("zhao",?33);
????????????People?person6?=?new?People("jacky",?44);
?
????????????ls4.Add(person4);
????????????ls4.Add(person5);
????????????ls4.Add(person6);
?
????????????ls4.Sort(MyComparFunc);
????????????Console.WriteLine("***********排序后的************");
?
????????????foreach?(var?p?in?ls4)
????????????{
????????????????Console.WriteLine(p.name+p.age);
????????????}
?
????????????Console.WriteLine("***********顛倒順序***********");
????????????ls4.Reverse();
????????????foreach?(var?p?in?ls4)
????????????{
????????????????Console.WriteLine(p.name+p.age);
????????????}
?
????????????/*
?????????????*?8.類型轉(zhuǎn)換??能夠?qū)⒓现械脑剞D(zhuǎn)換成隨意類型的元素,比方,
?????????????*?我們要將集合中的People轉(zhuǎn)換成為Racer對(duì)象Racer僅僅包括名字,沒(méi)有年紀(jì)
?????????????*?public?List<T?Output>ConvertAll<TOutput>(Converter<T,?TOutput>?converter);
?????????????*?public?delegate?T?Output?Converter<T?Input,?T?Output>(T?Input?input);??托付參數(shù)
?????????????*/
????????????List<Racer>?ls5?=?ls4.ConvertAll<Racer>((input)?=>?new?Racer(input.name));
????????????Console.WriteLine("***********轉(zhuǎn)換后的玩意***********");
?
????????????foreach?(var?r?in?ls5)
????????????{
????????????????Console.WriteLine(r.name);
????????????}
?
?
????????????/*9.僅僅讀集合
?????????????*?在創(chuàng)建完集合以后,肯定是可讀的,假設(shè)不是,他就不能再加入新元素了
?????????????*?可是,假設(shè)是覺(jué)得填充完成,不要再做改動(dòng)
?????????????*?能夠使用僅僅讀集合,使用AsReadOnly方法返回ReadOnlyCollection<T>
?????????????*?類型,它與List<>操作是一樣的,可是一但有改動(dòng)集合的操作,就會(huì)拋出異常
?????????????*?它屏蔽了通常的Add方法
?????????????*/
?
????????????IReadOnlyCollection<Racer>?persss?=?ls5.AsReadOnly();
?
????????????Console.WriteLine("輸出僅僅讀集合");
????????????foreach?(var?r?in?persss)
????????????{
????????????????Console.WriteLine(r.name);
????????????}
????????????Console.ReadKey();
????????}
????????public?static?int?MyComparFunc(People?p1,?People?p2)
????????{
????????????if?(p1.age==p2.age)
????????????{
????????????????return?0;
????????????}
????????????else?if?(p1.age?>?p2.age)
????????????{
????????????????return?1;
????????????}
????????????else
????????????{
????????????????return?-1;
????????????}
????????}
????}
????public?class?People
????{
????????public?string?name;
????????public?int?age;
????????public?People(string?name,?int?age)
????????{
????????????this.name?=?name;
????????????this.age?=?age;
????????}
????}
????public?class?Racer
????{
????????public?string?name;
????????public?Racer(string?name)
????????{
????????????this.name?=?name;
????????}
????}
}
C#中數(shù)組,ArrayList和List三者的差別
在C#中數(shù)組,ArrayList,List都可以存儲(chǔ)一組對(duì)象,那么三者究竟有何差別呢?
?
?
數(shù)組
數(shù)組在C#中最早出現(xiàn)的.在內(nèi)存中是連續(xù)存儲(chǔ)的,所以他的索引速度非???并且賦值與改動(dòng)元素也非常easy.
案例:
string?[]?s=new?string?[2];
//賦值
s[0]=”a”;
s[1]=”b”;
//改動(dòng)
s[1]=”aa”;
可是數(shù)組存在一些不足的地方.在數(shù)組的兩個(gè)數(shù)據(jù)間插入數(shù)據(jù)是非常麻煩的,并且在聲明數(shù)組的時(shí)候必須制定數(shù)組的長(zhǎng)度,數(shù)組的長(zhǎng)度過(guò)長(zhǎng),會(huì)造成內(nèi)存浪費(fèi),過(guò)界會(huì)造成數(shù)據(jù)溢出的錯(cuò)誤.假設(shè)在聲明數(shù)組的時(shí)候我們不清楚數(shù)組的長(zhǎng)度,就會(huì)變得非常麻煩.
針對(duì)數(shù)組的這些缺點(diǎn),C#中最先提供了ArrayList對(duì)象來(lái)克服這些缺點(diǎn).
?
ArrayList
ArrayList是命名空間System.Collections下的一部分,在使用該類時(shí)必須進(jìn)行引用,同一時(shí)候繼承了IList接口,提供了數(shù)據(jù)存儲(chǔ)和檢索.ArrayList對(duì)象的大小是依照當(dāng)中存儲(chǔ)的數(shù)據(jù)來(lái)動(dòng)態(tài)擴(kuò)充與收縮的.所以,在聲明ArrayList對(duì)象時(shí)并不須要指定它的長(zhǎng)度.
案例:
ArrayList??list1=new?ArrayList();
//新增數(shù)據(jù)
list1.Add(“cde”);
list1.Add(5678);
//改動(dòng)數(shù)據(jù)
list1[2]=34;
//移除數(shù)據(jù)
list1.Remove(0);
//插入數(shù)據(jù)
list1.Insert(0,”qwe”);
從上面樣例看,ArrayList好像是攻克了數(shù)組中的全部的缺點(diǎn),為什么又會(huì)有List?
我們從上面的樣例看,在List中,我們不僅插入了字符串cde,并且插入了數(shù)字5678.這樣在ArrayList中插入不同類型的數(shù)據(jù)是同意的.由于ArrayList會(huì)把全部插入當(dāng)中的數(shù)據(jù)當(dāng)做為object類型來(lái)處理,在我們使用ArrayList處理數(shù)據(jù)時(shí),非常可能會(huì)報(bào)類型不匹配的錯(cuò)誤,也就是ArrayList不是類型安全的.在存儲(chǔ)或檢索值類型時(shí)通常發(fā)生裝箱和拆箱操作,帶來(lái)非常呆的性能損耗.
裝箱與拆箱的概念:
簡(jiǎn)單的說(shuō):
裝箱:就是將值類型的數(shù)據(jù)打包到引用類型的實(shí)例中
比方將string類型的值abc賦給object對(duì)象obj
案例:
string?i=”abc”;
object?obj=(object)i;
?
拆箱:就是從引用數(shù)據(jù)中提取值類型
比方將object對(duì)象obj的值賦給string類型的變量i?:
object?obj=”abc”;
string?i=(string)obj;
?
裝箱與拆箱的過(guò)程是非常損耗性能的.
泛型List
由于ArrayList存在不安全類型與裝箱拆箱的缺點(diǎn),所以出現(xiàn)了泛型的概念.List類是ArrayList類的泛型等效類,他的大部分使用方法都與ArrayList相似,由于List類也繼承IList接口.最關(guān)鍵的卻別在于,在聲明List集合時(shí),我們同事須要為其聲明List集合內(nèi)數(shù)據(jù)的對(duì)象類型.
List<string>list=new?List<string>();
//新增數(shù)據(jù)
list.Add(“abc”);
//改動(dòng)數(shù)據(jù)
list[0]=”def”;
//移除數(shù)據(jù)
list.Remove(0);
上例中,假設(shè)我們往List集合中插入int數(shù)組123,IDE就會(huì)報(bào)錯(cuò),且不能通過(guò)編譯.這樣就避免了前面講的類型安全問(wèn)題與拆箱的性能問(wèn)題了.
?
總結(jié):數(shù)組的容量是固定的,您僅僅能一次獲取或設(shè)置一個(gè)元素的值,而ArrayList或List<T>的容量可依據(jù)須要自己主動(dòng)擴(kuò)充,改動(dòng),刪除或插入數(shù)據(jù).
數(shù)組能夠具有多個(gè)維度,而ArrayList或List<T>時(shí)鐘僅僅具有一個(gè)維度.可是您能夠輕松創(chuàng)建數(shù)組列表或列表的列表.特定類型(object除外)的數(shù)組的性能優(yōu)于ArrayList的性能.這是由于ArrayList的元素屬于object類型;所以在存儲(chǔ)或檢索值類型時(shí)通常發(fā)生裝箱和拆箱操作.只是,在不須要又一次分配時(shí)(即最初的容量十分接近列表的最大容量),List<T>的性能與同類型的數(shù)組十分相近.
?
在決定使用List<T>還是使用ArrayList類(兩者具有類似的功能)時(shí),記住List<T>類在大多數(shù)情況下運(yùn)行的更好而且是類型安全的.假設(shè)對(duì)List<T>類的類型T使用引用類型,則兩個(gè)類的行為是全然同樣的.可是,假設(shè)對(duì)類型T使用值類型,則須要考慮實(shí)現(xiàn)和裝箱操作.
?
?
?
本文摘自 :https://blog.51cto.com/u