C#高级编程四十八天----列表

C#中的List

C#中deList怎么样?List<T>类是ArrayList类的泛型等效类,该类使用大小可按需动态增长的数组实现List<T>泛型接口.

泛型的好处:它为使用C#语言编写面向对象程序增加了极大的效力和灵活性,不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转化,所以性能得到提高.

性能注意事项:再决定使用List<T>还是使用ArrayList类(两者具有类似的功能)时,记住IList<T>类在大多数情况下执行得更好并且是类型安全的.如果对IList<T>类的类型T使用引用类型,则两个类的行为是完全相同的,但是如果对类型T使用值类型,则需要考虑实现和装箱问题.

C#List的基础常用方法:

一.声明:

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);

以一个集合作为参数创建List:

string[] temArr = { "Ha", "Hunter", "Tom", "Lily", "Jay", "Jim", "Kuku", "Locu" };

List<string> testList = new List<string>(temArr);

二.添加元素:

1. List.Add( Titem)添加一个元素

例如: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位置添加一个元素

例: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)删除一个值

例:mList.Remove(“hahaha”);

2.List.RemoveAt(int index);删除下标为index 的元素

例:mList.RemoveAt(0);

3.List.RemoveRange(int index , int count);从下标index开始,删除count个元素

例:mList.RemoveRange(3,2);

五.判断某个元素是否在该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里面元素顺序反转:

  List. Reverse ()可以不List. Sort ()配合使用,达到想要的效果

  例:

  mList.Sort();

  八、List清空:

  List. Clear ()

  例:

  mList.Clear();

  九、获得List中元素数目:

  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);

/*如果不指定list容量大小,默认是0,只要有元素加入时,会自动扩展到4,如果第五个元素加入时

* 就变成了8,第九个元素加入时,就变成了16

* 可以看出,容量总是成倍的增长,扩展时要重新开辟内存,这样会影响效率,如果事先知道元素个数,

* 或者可能判断个数,最好给出个大体的容量值

* 我们加入了三个元素,就设容量大小为4.注意:设为4不是说只能存放四个元素

* 而是说,如果超出四个,一样会成倍扩展,这样做是为了减小扩展带来的开销

*/

/*

* 这个方法作用是清楚多于的没有用的内存空间.例如:如果开辟大小为100

* 但是我们只用了4个,其余的不用,是不是浪费

* 本方法调用时会检查元素个数是不是占到了容量的90%以上

* 如果是,则不进行回收

*/

list.TrimExcess();

/*ArrayList方法和List<T>用法一样,不同的是,它是对象集合

* 参数是object这样会有装箱拆箱的可能

* 所以尽量使用List<>

*/

/*

* 1.初始化集合器

* C#3.0开始,提供了初始化功能,但是并没有反映到IList代码中

* 在IList中,一样也是把它转化成Add方法调用

*/

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

/*

* 2.添加元素AddRange()方法可以一次性添加一批对象

*/

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

//参数是一个必须可能迭代的对象,也可能是一个数组

list.AddRange(new People[] { new People("aladdin", 20), new People("zhao", 6) });

//构造传入批量参数,与AddRange效果一样

List<People> myList = new List<People>(new People[] { new People("aladdin", 20), new People("zhao", 6) });

/*

* 3.插入元素

* 使用Insert()方法,可以在指定位置插入元素

* 例 我们在1的位置插入,则最后变成了aladdin jacky zhao..插入意思就是,这个位我占了,

* 以前占这位的和他之后的,通通往后移一位

*/

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迭代器来实现

/*

* public delegate void Action<T>(T obj);用委托作为参数

*/

Console.WriteLine("********用foreach方法输出********");

myList.ForEach(param => Console.WriteLine(param.name));

/*

* 5.删除元素

* 删除元素可以使用RemoveAt()直接传入索引器值

* 将第一个元素直接删除

*/

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);

}

/*

* 从结果可以看出,名称为jacky的元素被删除了

* 下面说一下Remove方法的删除过程

* 用IndexOf方法确定出对象的索引,然后按索引删除

* 在IndexOf方法内,首先检查元素是不是实现了IEquatable接口,如果是,就调用这个

* 这个接口的Equals()方法

* 如果没有实现,则掉用Object中的Equals方法比较元素(也就是地址比较)

* 以上我们删除per3,很明显是一个地址,所以被删除了

* 下面我们改装People,实现了IEquatable<People,在

* 比较方法中,始终返回false,同per3会比较失败,不会被删除

* 结果三个都在

* 如果要删除对象,最好使用索引直接删除,因为Remove方法经历了一系列过程后,最后才按索引删除!

*

* RemoveRange()方法删除一个范围

* 第一个参数:开始位置;第二个参数:个数

* lists2.RemoveRange(1,2);

* 使用foreach查看批量删除后的结果

* foreach (var per in lists2)

*{

*   Console.WriteLine(per.name);

*}

*

*/

/*

* 6.搜索

* 搜索有很多方式,可以使用

* IndexOf,LastIndexOf,FindIndex,FindLastIndex,Find,FindLast

* 如果指示查看元素的存在情况,可以使用Exists()方法

* IndexOf()方法需要将一个对象做参数,如果存在,就返回本元素在集合中的索引,

* 如果找不到就返回-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);

//为了使用默认的地址比较,我们把People的接口暂时去掉

int index = ls3.IndexOf(person3);

Console.WriteLine("per3的索引 : "+index);

//还可以指定搜索范围 从第三个开始,范围长度为1

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

Console.WriteLine(index2);

//FindIndex()方法用来搜索带有一定特性的元素

//用委托做参数 public delegate bool Predicate<T>(T obj);

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

Console.WriteLine(index3);//2

//FindLastIndex是从 后面查第一个出现的元素,因为我们这里没有重复元素,所以

//体现不出它只能查找一个,就停下来的效果

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);

/*

* 如果要查找所有的匹配元素,而不是找到第一个就停下来,就是用FindAll()方法

* 我们查找所有年纪等于100的对象,3个都符合

*/

List<People> newList = ls3.FindAll(p => p.age == 100);

Console.WriteLine("**********查找所有**********");

foreach (var p in newList)

{

Console.WriteLine(p.name);

}

/*

* 7.排序

* List可以利用Sort方法排序,实现算符是快速排序

* 本方法有好几个重载

* public void Sort()只对元素实现了IComparable才能使用这个方法 ,如果实现了则,可以直接调用一次sort之后,就排好序了

* public void Sort(Comparison<T> comparison)我们的Person并没有实现那个接口,所以要用泛型委托当参数的方法

* public void Sort(IComparer<T>(T x , T y))泛型接口当参数 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.类型转换  可以将集合中的元素转换成任意类型的元素,比如,

* 我们要将集合中的People转换成为Racer对象Racer只包含名字,没有年纪

* public List<T Output>ConvertAll<TOutput>(Converter<T, TOutput> converter);

* public delegate T Output Converter<T Input, T Output>(T Input input);  委托参数

*/

List<Racer> ls5 = ls4.ConvertAll<Racer>((input) => new Racer(input.name));

Console.WriteLine("***********转换后的玩意***********");

foreach (var r in ls5)

{

Console.WriteLine(r.name);

}

/*9.只读集合

* 在创建完集合以后,肯定是可读的,如果不是,他就不能再添加新元素了

* 但是,如果是认为填充完毕,不要再做修改

* 可以使用只读集合,使用AsReadOnly方法返回ReadOnlyCollection<T>

* 类型,它与List<>操作是一样的,但是一但有修改集合的操作,就会抛出异常

* 它屏蔽了通常的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#中数组,ArrayList和List三者的区别

在C#中数组,ArrayList,List都能够存储一组对象,那么三者到底有何区别呢?

数组

数组在C#中最早出现的.在内存中是连续存储的,所以他的索引速度非常快,而且赋值与修改元素也很简单.

案例:

string [] s=new string [2];

//赋值

s[0]=”a”;

s[1]=”b”;

//修改

s[1]=”aa”;

但是数组存在一些不足的地方.在数组的两个数据间插入数据是很麻烦的,而且在声明数组的时候必须制定数组的长度,数组的长度过长,会造成内存浪费,过界会造成数据溢出的错误.如果在声明数组的时候我们不清楚数组的长度,就会变得很麻烦.

针对数组的这些缺点,C#中最先提供了ArrayList对象来克服这些缺点.

ArrayList

ArrayList是命名空间System.Collections下的一部分,在使用该类时必须进行引用,同时继承了IList接口,提供了数据存储和检索.ArrayList对象的大小是按照其中存储的数据来动态扩充与收缩的.所以,在声明ArrayList对象时并不需要指定它的长度.

案例:

ArrayList  list1=new ArrayList();

//新增数据

list1.Add(“cde”);

list1.Add(5678);

//修改数据

list1[2]=34;

//移除数据

list1.Remove(0);

//插入数据

list1.Insert(0,”qwe”);

从上面例子看,ArrayList好像是解决了数组中的所有的缺点,为什么又会有List?

我们从上面的例子看,在List中,我们不仅插入了字符串cde,而且插入了数字5678.这样在ArrayList中插入不同类型的数据是允许的.因为ArrayList会把所有插入其中的数据当做为object类型来处理,在我们使用ArrayList处理数据时,很可能会报类型不匹配的错误,也就是ArrayList不是类型安全的.在存储或检索值类型时通常发生装箱和拆箱操作,带来很呆的性能损耗.

装箱与拆箱的概念:

简单的说:

装箱:就是将值类型的数据打包到引用类型的实例中

比如将string类型的值abc赋给object对象obj

案例:

string i=”abc”;

object obj=(object)i;

拆箱:就是从引用数据中提取值类型

比如将object对象obj的值赋给string类型的变量i :

object obj=”abc”;

string i=(string)obj;

装箱与拆箱的过程是很损耗性能的.

泛型List

因为ArrayList存在不安全类型与装箱拆箱的缺点,所以出现了泛型的概念.List类是ArrayList类的泛型等效类,他的大部分用法都与ArrayList相似,因为List类也继承IList接口.最关键的却别在于,在声明List集合时,我们同事需要为其声明List集合内数据的对象类型.

List<string>list=new List<string>();

//新增数据

list.Add(“abc”);

//修改数据

list[0]=”def”;

//移除数据

list.Remove(0);

上例中,如果我们往List集合中插入int数组123,IDE就会报错,且不能通过编译.这样就避免了前面讲的类型安全问题与拆箱的性能问题了.

总结:数组的容量是固定的,您只能一次获取或设置一个元素的值,而ArrayList或List<T>的容量可根据需要自动扩充,修改,删除或插入数据.

数组可以具有多个维度,而ArrayList或List<T>时钟只具有一个维度.但是您可以轻松创建数组列表或列表的列表.特定类型(object除外)的数组的性能优于ArrayList的性能.这是因为ArrayList的元素属于object类型;所以在存储或检索值类型时通常发生装箱和拆箱操作.不过,在不需要重新分配时(即最初的容量十分接近列表的最大容量),List<T>的性能与同类型的数组十分相近.

在决定使用List<T>还是使用ArrayList类(两者具有类似的功能)时,记住List<T>类在大多数情况下执行的更好并且是类型安全的.如果对List<T>类的类型T使用引用类型,则两个类的行为是完全相同的.但是,如果对类型T使用值类型,则需要考虑实现和装箱操作.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-24 11:50:00

C#高级编程四十八天----列表的相关文章

C#高级编程四十三天----Lambda表达式

Lambda表达式 案例: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace lambda表达式 { class Program { public delegate int del(int i); static void Main(string[] args) { List<string> fr

C#高级编程五十八天----并行集合

并行集合 对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行訪问.常常要做的就是对一些队列进行加锁-解锁,然后运行类似插入,删除等等相互排斥操作. .NET4提供了一些封装好的支持并行操作数据容器,能够降低并行编程的复杂程度. 并行集合的命名空间:System.Collections.Concurrent 并行容器: ConcurrentQueue ConcurrentStack ConcurrentBag: 一个无序的数据结构集,当不考虑顺序时很实用. BlockingCollec

C#高级编程六十八天---LINQ小结

LINQ小结 一.LINQ是什么 LINQ也就是Language Interrated Query的缩写,怎么一个缩写法我也不明白,即语言集成查询,是微软在.NET3.5中提出的一项新技术,LINQ主要包含四个组件,下面看一下LINQ的一个架构图: 简单的介绍一些四个组件: 1.Linq to SQL 组件----可以查询基于关于数据的数据(微软本身只是实现了对SQL Server的查询,可以对数据库中的数据进行查询,修改,插入删除,排序等操作) 2.LINQ to Dataset组件----可

C#高级编程四十九天----队列

队列 1.Queue定义 System.Collections.Queue类表示对象的先进先出集合,存储在Queue(队列)中的对象在一端插入,从还有一端移除. 2.长处 (1).能对集合进行顺序处理(先进先出) (2)能接受null值,而且同意反复的元素 3.Queue的构造器 构造器函数 凝视 Queue() 初始化Queue类的新实例,该实例为空,具有默认初始容量(32)并使用默认增长因子(2.0) Queue(ICollection) 初始化Queue类的新实例,该实例包括从指定集合复制

C#高级编程四十六天----正则表达式

正则表达式 1.定义一个Regex类的实例 Regex regex=new Regex(""); 这里初始化参数就是一个正则表达式,"\d"表示配置数字 2.判断是否匹配 判断一个字符串,是否匹配一个正则表达式,在Regex对象中,可以使用Regex.IsMatch(string )方法. Regex regex = new Regex(@"\d"); bool b1=regex.IsMatch("abc"); //返回值为f

C#高级编程四十七天----集合接口和类型

集合接口和类型 前面介绍了数组和Array类实现的接口.数组的大小是固定的.如果元素个数是动态的,就应私用集合类. List<T>是与数组相当的集合类.还有其他类型的集合:队列,栈,链表和字典. 大多数集合类都可在System.Collections和System.Collections.Generic名称空间中找到.泛型集合类位于System.Collections.Generic名称空间中;专用于特定类型的集合类位于System.Collections.Specialized名称空间中.线

C#高级编程三十八天----运算符

运算符 类别 运算符 算术运算符 + - * / 逻辑运算符 & | ^ ~ && || ~ 字符串连接运算符 + 增量和减量运算符 ++ -- 移位运算符 << >> 比较运算符 == != < > <= >= 赋值运算符 = += -= *= /=  %=  &=  |= ^=  >>=  <<= 成员访问运算符运算符(用于对象和结构) . 索引运算符(用于数组和所引起) [] 类型转换运算符 ()

C#高级编程四十天----运算符重载

运算符重载 所谓的运算符重载是指允许用户使用用户定义的类型编写表达式的能力. 例如,通常需要编写类似与以下内容的代码,入江两个数字相加,很明显,sum是两个数字之和. int i=5,j=4; int sum = i+j; 如果可以使用代表附属的用户定义的类型来编写相同类型的表达式,那当然是最好不过的了: Complex i=5; Complex sum=i+j; 运算符重载允许为用户定义的类型重载(即指明明确的含义)诸如"+"这样的运算符.如果不进行重载,则用户需要编写以下代码: C

C#高级编程四十四天-----string和stringbuilder

System.String类 首先string类是静态的,System.String是最常用的字符串操作类,可以帮助开发者完成绝大部分的字符串操作功能,使用方便. 1.比较字符串 比较字符串是指按照字典排序规则,判定两个字符的相对大小.按照点点规则,在一本英文字典中,出现在前面的单词小于出现在后面的单词.在string类中,常用的比较字符串的方法包括Compare,CompareTo,CompareOrdinal以及Equals,下面进行详细的介绍. Compare()方法是string类的静态