當(dāng)前位置:首頁 > IT技術(shù) > Windows編程 > 正文

C#高級編程四十八天----列表
2021-08-06 16:21:56

C#中的List

C#中deList怎么樣?List<T>類是ArrayList類的泛型等效類,該類使用大小可按需動(dòng)態(tài)增長的數(shù)組實(shí)現(xiàn)List<T>泛型接口.

?

泛型的優(yōu)點(diǎn):它為使用C#語言編寫面向?qū)ο蟪绦蛱砑恿藰O大的效力和靈活性,不會強(qiáng)行對值類型進(jìn)行裝箱和拆箱,或?qū)σ妙愋瓦M(jìn)行向下強(qiáng)制類型轉(zhuǎn)化,所以性能得到提高.

?

性能注意事項(xiàng):再決定使用List<T>還是使用ArrayList類(兩者具有類似的功能)時(shí),記住IList<T>類在大多數(shù)情況下運(yùn)行得更好而且是類型安全的.假設(shè)對IList<T>類的類型T使用引用類型,則兩個(gè)類的行為是全然同樣的,可是假設(shè)對類型T使用值類型,則須要考慮實(shí)現(xià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開始,刪除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對象加到集合中

????????????List<People>?list?=?new?List<People>(4);

????????????list.Add(p1);

????????????list.Add(p2);

????????????list.Add(p3);

????????????/*假設(shè)不指定list容量大小,默認(rèn)是0,僅僅要有元素增加時(shí),會自己主動(dòng)擴(kuò)展到4,假設(shè)第五個(gè)元素增加時(shí)

?????????????*?就變成了8,第九個(gè)元素增加時(shí),就變成了16

?????????????*?能夠看出,容量總是成倍的增長,擴(kuò)展時(shí)要又一次開辟內(nèi)存,這樣會影響效率,假設(shè)事先知道元素個(gè)數(shù),

?????????????*?或者可能推斷個(gè)數(shù),最好給出個(gè)大體的容量值

?????????????*?我們增加了三個(gè)元素,就設(shè)容量大小為4.注意:設(shè)為4不是說僅僅能存放四個(gè)元素

?????????????*?而是說,假設(shè)超出四個(gè),一樣會成倍擴(kuò)展,這樣做是為了減小擴(kuò)展帶來的開銷?????????????

?????????????*/

?

?

????????????/*

?????????????*?這種方法作用是清楚多于的沒實(shí)用的內(nèi)存空間.比如:假設(shè)開辟大小為100

?????????????*?可是我們僅僅用了4個(gè),其余的不用,是不是浪費(fèi)

?????????????*?本方法調(diào)用時(shí)會檢查元素個(gè)數(shù)是不是占到了容量的90%以上

?????????????*?假設(shè)是,則不進(jìn)行回收

?????????????*/

????????????list.TrimExcess();

?

?

????????????/*ArrayList方法和List<T>使用方法一樣,不同的是,它是對象集合

?????????????*?參數(shù)是object這樣會有裝箱拆箱的可能

?????????????*?所以盡量使用List<>???????????

?????????????*/

?

?

????????????/*

?????????????*?1.初始化集合器

?????????????*?C#3.0開始,提供了初始化功能,可是并沒有反映到IList代碼中

?????????????*?在IList中,一樣也是把它轉(zhuǎn)化成Add方法調(diào)用??????????????

?????????????*/

?

????????????List<int>?l2?=?new?List<int>()?{?1,?2,?3,?4,?5?};

?

????????????/*

?????????????*?2.加入元素AddRange()方法能夠一次性加入一批對象?????????????

?????????????*/

????????????List<People>?lists?=?new?List<People>(10);

????????????//參數(shù)是一個(gè)必須可能迭代的對象,也可能是一個(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()方法,能夠在指定位置插入元素

?????????????*?例?我們在1的位置插入,則最后變成了aladdin?jacky?zhao..插入意思就是,這個(gè)位我占了,

?????????????*?曾經(jīng)占這位的和他之后的,通通往后移一位

?????????????*/

????????????myList.Insert(1,?new?People("Jacky",?22));

?

????????????foreach?(var?p?in?myList)

????????????{

????????????????Console.WriteLine(p.name);

????????????}

?

????????????/*

?????????????*4.訪問元素

?????????????*ArrayList和List<T>都是提供了索引器來訪問的

?????????????*/

????????????Console.WriteLine("*********訪問元素********");

?

????????????for?(int?i?=?0;?i?<?myList.Count;?i++)

????????????{

????????????????Console.WriteLine(myList[i].name);

????????????}

????????????//還能夠使用foreach迭代器來實(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的元素被刪除了

?????????????*?以下說一下Remove方法的刪除過程

?????????????*?用IndexOf方法確定出對象的索引,然后按索引刪除

?????????????*?在IndexOf方法內(nèi),首先檢查元素是不是實(shí)現(xiàn)了IEquatable接口,假設(shè)是,就調(diào)用這個(gè)

?????????????*?這個(gè)接口的Equals()方法

?????????????*?假設(shè)沒有實(shí)現(xiàn),則掉用Object中的Equals方法比較元素(也就是地址比較)

?????????????*?以上我們刪除per3,非常明顯是一個(gè)地址,所以被刪除了

?????????????*?以下我們改裝People,實(shí)現(xiàn)了IEquatable<People,在

?????????????*?比較方法中,始終返回false,同per3會比較失敗,不會被刪除

?????????????*?結(jié)果三個(gè)都在

?????????????*?假設(shè)要?jiǎng)h除對象,最好使用索引直接刪除,由于Remove方法經(jīng)歷了一系列過程后,最后才按索引刪除!

?????????????*?

?????????????*?RemoveRange()方法刪除一個(gè)范圍

?????????????*?第一個(gè)參數(shù):開始位置;第二個(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è)對象做參數(shù),假設(shè)存在,就返回本元素在集合中的索引,

?????????????*?假設(shè)找不到就返回-1,IndexOf還能夠使用IEquatable接口來比較元素???????????????????????????????????????

?????????????*/

????????????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è)開始,范圍長度為1

????????????int?index2?=?ls3.IndexOf(person3,?2,?1);

????????????Console.WriteLine(index2);

????????????//FindIndex()方法用來搜索帶有一定特性的元素

????????????//用托付做參數(shù)?public?delegate?bool?Predicate<T>(T?obj);

????????????int?index3?=?ls3.FindIndex(param?=>?param.name.Equals(""));

?

????????????Console.WriteLine(index3);//2

????????????//FindLastIndex是從?后面查第一個(gè)出現(xiàn)的元素,由于我們這里沒有反復(fù)元素,所以

????????????//體現(xiàn)不出它僅僅能查找一個(gè),就停下來的效果

????????????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è)就停下來,就是用FindAll()方法

?????????????*?我們查找全部年紀(jì)等于100的對象,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()僅僅對元素實(shí)現(xiàn)了IComparable才干使用這種方法?,假設(shè)實(shí)現(xiàn)了則,能夠直接調(diào)用一次sort之后,就排好序了

?????????????*?public?void?Sort(Comparison<T>?comparison)我們的Person并沒有實(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對象Racer僅僅包括名字,沒有年紀(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è)是覺得填充完成,不要再做改動(dòng)

?????????????*?能夠使用僅僅讀集合,使用AsReadOnly方法返回ReadOnlyCollection<T>

?????????????*?類型,它與List<>操作是一樣的,可是一但有改動(dòng)集合的操作,就會拋出異常

?????????????*?它屏蔽了通常的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都可以存儲一組對象,那么三者究竟有何差別呢?

?

?

數(shù)組

數(shù)組在C#中最早出現(xiàn)的.在內(nèi)存中是連續(xù)存儲的,所以他的索引速度非???并且賦值與改動(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ù)組的長度,數(shù)組的長度過長,會造成內(nèi)存浪費(fèi),過界會造成數(shù)據(jù)溢出的錯(cuò)誤.假設(shè)在聲明數(shù)組的時(shí)候我們不清楚數(shù)組的長度,就會變得非常麻煩.

針對數(shù)組的這些缺點(diǎn),C#中最先提供了ArrayList對象來克服這些缺點(diǎn).

?

ArrayList

ArrayList是命名空間System.Collections下的一部分,在使用該類時(shí)必須進(jìn)行引用,同一時(shí)候繼承了IList接口,提供了數(shù)據(jù)存儲和檢索.ArrayList對象的大小是依照當(dāng)中存儲的數(shù)據(jù)來動(dòng)態(tài)擴(kuò)充與收縮的.所以,在聲明ArrayList對象時(shí)并不須要指定它的長度.

案例:

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),為什么又會有List?

我們從上面的樣例看,在List中,我們不僅插入了字符串cde,并且插入了數(shù)字5678.這樣在ArrayList中插入不同類型的數(shù)據(jù)是同意的.由于ArrayList會把全部插入當(dāng)中的數(shù)據(jù)當(dāng)做為object類型來處理,在我們使用ArrayList處理數(shù)據(jù)時(shí),非常可能會報(bào)類型不匹配的錯(cuò)誤,也就是ArrayList不是類型安全的.在存儲或檢索值類型時(shí)通常發(fā)生裝箱和拆箱操作,帶來非常呆的性能損耗.

裝箱與拆箱的概念:

簡單的說:

裝箱:就是將值類型的數(shù)據(jù)打包到引用類型的實(shí)例中

比方將string類型的值abc賦給object對象obj

案例:

string?i=”abc”;

object?obj=(object)i;

?

拆箱:就是從引用數(shù)據(jù)中提取值類型

比方將object對象obj的值賦給string類型的變量i?:

object?obj=”abc”;

string?i=(string)obj;

?

裝箱與拆箱的過程是非常損耗性能的.

泛型List

由于ArrayList存在不安全類型與裝箱拆箱的缺點(diǎn),所以出現(xiàn)了泛型的概念.List類是ArrayList類的泛型等效類,他的大部分使用方法都與ArrayList相似,由于List類也繼承IList接口.最關(guān)鍵的卻別在于,在聲明List集合時(shí),我們同事須要為其聲明List集合內(nèi)數(shù)據(jù)的對象類型.

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就會報(bào)錯(cuò),且不能通過編譯.這樣就避免了前面講的類型安全問題與拆箱的性能問題了.

?

總結(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類型;所以在存儲或檢索值類型時(shí)通常發(fā)生裝箱和拆箱操作.只是,在不須要又一次分配時(shí)(即最初的容量十分接近列表的最大容量),List<T>的性能與同類型的數(shù)組十分相近.

?

在決定使用List<T>還是使用ArrayList類(兩者具有類似的功能)時(shí),記住List<T>類在大多數(shù)情況下運(yùn)行的更好而且是類型安全的.假設(shè)對List<T>類的類型T使用引用類型,則兩個(gè)類的行為是全然同樣的.可是,假設(shè)對類型T使用值類型,則須要考慮實(shí)現(xiàn)和裝箱操作.

?

?

?

?
?
?
?

本文摘自 :https://blog.51cto.com/u

開通會員,享受整站包年服務(wù)立即開通 >