什么是列表和列表的创建添加遍历访问
什么是列表和列表的创建添加遍历访问
集合类 列表List
当我们有很多类型⼀样的数据的时候,前⾯我们⼀般使⽤数组来进⾏管理,但是这样有个
缺点就是数组的⼤⼩是固定的。如果我们很多类型⼀样的数据,⽐如游戏得分,我们可以
集合类来进⾏管理,⽐如列表List,我们可以使⽤列表List很⽅便的添加数据,删除数据
还有其他对数据的操作。
列表的创建和使用
演示:
List<int> scoreList = new List<int>();
new List<int>(){1,2,3}
new List<string>(){"one","two"}
var scoreList = new List<int>()
创建列表的实践:
//列表创建的演示
//<>泛型语法
List<int> list = new List<int>();//不报错的条件:1. 有尖括号,和列表类型 2. 有对应的命名空间 using System.Collections.Generic
List<string> list2 = new List<string>();//尖括号里放置了什么类型,就代表集合里面存储了什么类型
给列表初始值的实践
//设置初始值的演示
//使用 { }
List<int> list = new List<int>() { 321,22,3,588,989,52,55,4,111};
与数组的区别,列表集合后续也可以随意添加删除某个数据
向集合中添加数据
样式:
scoreList.Add(12);
scoreList.Add(45);
实践:
//向列表集合中添加数据的演示
list.Add(900);
list.Add(65);//每次调用 Add 都会向集合中添加新的数据
访问List里的数据
//数据访问
//[] 里面的数字代表索引
Console.WriteLine(list[3]);
利用count属性遍历List
//遍历
//for循环 Count属性
for(int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
顺便一提,也可以用索引去修改值
//索引修改数据
list[1] = 0;
列表的内部数据管理
关于列表的更多内容
1,列表内部数据是使⽤数组进⾏的存储,⼀个空的列表内部会有⼀个⻓度为0的数组,当
给列表中添加元素的时候,列表的容量会扩⼤为4,如果添加第5个的时候,列表的⼤⼩
会重新设置为8,如果添加第9个元素,列表容量会扩⼤为16,依次增加。当列表的中的
容量发⽣改变的时候,它会创建⼀个新的数组,使⽤Array.Copy()⽅法将旧数组中的元素
复制到新数组中。为了节省时间,如果事先知道要存储的数据的个数,就可以利⽤列表的
构造函数指定列表的容量⼤⼩,⽐如下⾯的
List intlist = new List(10);创建了⼀个初始容量为10的列表,当容量不够⽤的时
候,每次都会按照原来容量的2倍进⾏扩容。
我们可以通过Capacity属性获取和设置容量
intList.Capacity = 100;
没有添加任何数据的情况
//输出容量和 Count
List<int> list = new List<int>();
Console.WriteLine(list.Count+" "+list.Capacity);
//0 0 没有添加任何元素
像list里添加数据之后再观察
//添加数据
list.Add(12);
Console.WriteLine(list.Count + " " + list.Capacity);
//1 4 count为1,列表长度/容量默认为4
list.Add(12);
list.Add(12);
list.Add(12);
list.Add(12);
Console.WriteLine(list.Count + " " + list.Capacity);
//5 8 数据超过四个之后,又创建了容量为8的新数组
列表指定初始容量
List<int> list = new List<int>(40);//( )里的数字代表了初始容量
Console.WriteLine(list.Count + " " + list.Capacity);
//0 40
列表的一些常见操作
详解列表的遍历
方法1 for循环
for循环,遍历所有的索引,通过索引访问列表中的元素
for(int i=0;i<list.Count;i++){
//循环体list[i]
}
方法2 foreach循环
foreach遍历
foreach(int temp in list){ //依次取得list中的每⼀个元素赋值给temp,并执⾏循环体
//循环体 temp
}
foreach遍历的使用:
//foreach循环
List<int> list1 = new List<int>(40);
list.Add(15464);
list.Add(16);
list.Add(151);
foreach(int temp in list)
{
Console.WriteLine(temp);
}
操作列表的属性和⽅法
1,Capacity获取容量⼤⼩
2,Add()⽅法添加元素Unity 1143 C#编程-第⼆季-⾯向对象
25
3,Insert()⽅法插⼊元素
4,[index]访问元素
5,Count属性访问元素个数
6,RemoveAt()⽅法移除指定位置的元素
7,IndexOf()⽅法取得⼀个元素所在列表中的索引位置
LastIndexOf()上⾯的⽅法是从前往后搜索,这个是从后往前搜索,搜索到满⾜条件的
就停⽌
上⾯的两个⽅法,如果没有找到指定元素就返回-1
8,Sort()对列表中是元素进⾏从⼩到⼤排序
增加数据Add
List<int> list = new List<int>() { 54, 55, 333, 215, 68451, 2, 3, };
Console.WriteLine(list.Capacity);//8
list.Add(800);
Console.WriteLine(list[2]);//333
插入数据Insert
List<int> list = new List<int>() { 54, 55, 333, 215, 68451, 2, 3, };
list.Insert(3, 988);//(索引前,数据 )
foreach(int temp in list)
{
Console.WriteLine(temp);
}//通过遍历判断是否插入成功
数据的删除Remove
指定数据删除Remove
//数据的删除
list.Remove(54);//Remove 移除指定的数据
ShowList(list);//54消失了
//注意 如果有两个相同的数据 只会移除第一个
指定索引删除RemoveAt
//索引删除数据
list.RemoveAt(0);
ShowList(list);//第一个索引处的数据54消失了
从前往后查询数据IndexOf
List<int> list = new List<int>() { 54, 2,55, 333, 215, 68451, 2, 3, };
//查询数据
Console.WriteLine(list.IndexOf(2));//1
//有两个相同数据,只会查询到第一个
查询到的是数据所在的索引位置
如果查询的数据不存在?
//查询数据
Console.WriteLine(list.IndexOf(10000000));//-1
//有两个相同数据,只会查询到第一个
返回-1
从后往前查询数据LastIndexOf
List<int> list = new List<int>() { 54, 2,55, 333, 215, 68451, 2, 3, };
//反序查找
Console.WriteLine(list.LastIndexOf(2));// 6
列表排序Sort
//排序
list.Sort();//从小到大排序
ShowList(list);
泛型类
泛型是什么?
通过参数化类型来实现在同⼀份代码上操作多种数据类型。利⽤“参数化类型”将类型抽象
化,从⽽实现灵活的复⽤。
泛型类
定义⼀个泛型类就是指的是,定义⼀个类,这个类中某些字段的类型是不确定的,这些类
型可以在类构造的时候确定下来,举例:
创建⼀个类处理int类型和double类型的相加
样式
class ClassA<T>{
private T a;
private T b;
public ClassA(T a,T b){
this.a = a ;this.b = b;
}
public T GetSum(){
return a+“”+b;
}
}
使用
先定义一个类拿到a+b的值
//先定义一个方法,用来取得a+b的值
//ab成员 构造函数赋值 方法求和
class ClassA
{
private int a;
private int b;
public ClassA(int a, int b)
{
this.a = a;
this.b = b;
}
public int GetSum()
{
return a + b;
}
}
使用这个类
static void Main(string[] args)
{
ClassA a = new ClassA(65,66);
Console.WriteLine(a.GetSum());
//虽然这样能得到结果,但是局限性: 只能得到两个整型相加,那么如果两个double类型相加怎么办
//又要创建新的类,很麻烦
}
使用泛型让这个类同时能处理多个类型
class ClassA<T>//Type 用ClassA创建对象的时候,你必须指定数据类型
{
private T a;
private T b;
public ClassA(T a, T b)
{
this.a = a;
this.b = b;
}
public T GetSum()
{
//注意 因为 T 类型不确定,这里声明动态类型
dynamic numn1 = a;
dynamic numn2 = b;
dynamic result = numn1 + numn2;
return result;//把结果强赛进T类型
}
用泛型类声明对象
//泛型类声明对象
ClassA<double> a = new ClassA<double>(45.3,99.3);//144.6
类中的ToString方法
ToString方法
作用:把一个对象转换成字符串
//类的对象 toString
Program p = new Program();
Console.WriteLine(p.ToString());//输出 泛型.Program
Console.WriteLine(p);//输出 泛型.Program
对象相加
Program p1 = new Program();
Program p2 = new Program();
//通过字符串组拼相加
string str = p1.ToString() + p2.ToString();
Console.WriteLine(str);//输出 泛型.Program泛型.Program
两个对象是不能相加的,只能通过转换成字符串相加
类的重写
定义一个新的类
class Student
{
private int age;
private string name;
public Student(int age, string name)//用构造函数对成员进行赋值
{
this.age = age;
this.name = name;
}
}
试着打印
Student s = new Student(30, "小兰");
Console.WriteLine(s);//泛型2_更高版本的_net.Student 打印出来的是对象,不是数据
需要重写方法来实现数据的打印
//在子类里重写父类的 ToString方法
//在这个重写的方法里组拼两个数据
public override string ToString()
{
string result = age + ":" + name;
return result;
}
重新运行输出代码,得到的是子类的数据这次
Student s = new Student(30, "小兰");
Console.WriteLine(s);
//30:小兰
原理:打印对象的时候默认会返回ToString,而这个方法打印的结果是对象的详细地址,那么只许愿重写这个方法就好了
用vs自动生成ToString重写
快速操作和重构 - 生成重写
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pxCdqpUq-1680947174958)(C:\Users\CoreDawg\AppData\Roaming\Typora\typora-user-images\image-20230408162402947.png)]
生成的重写
public override string ToString()
{
return base.ToString();
}
泛型方法
泛型方法
用普通方法对a+b进行求和
//普通方法
public static int GetSumk(int a, int b)
{
int result = a + b;
return result;
}
//通过类名调用
//当两个方法处于一个类的时候,不需要加类名前缀
Console.WriteLine(GetSumk(34, 55));
同样拥有不灵活的问题
用泛型方法实现
public static T GetSumk<T>(T a, T b)
{
dynamic num1 = a;
dynamic num2 = b;
dynamic dynamic1 = num2 + num1;
dynamic result = dynamic1;
return (T)result;
}
输出
Console.WriteLine(GetSumk<int>(34, 55));
创建自己的MyList列表
使⽤泛型和索引器来实现⼀个我们⾃⼰的集合类MyList
有下⾯的⽅法和属性
1,Capacity获取容量⼤⼩
2,Add()⽅法添加元素
3,Insert()⽅法插⼊元素
4,[index]访问元素(索引器)
5,Count属性访问元素个数
6,RemoveAt()⽅法移除指定位置的元素
7,IndexOf()⽅法取得⼀个元素所在列表中的索引位置
LastIndexOf()上⾯的⽅法是从前往后搜索,这个是从后往前搜索,搜索到满⾜条件的就
停⽌
上⾯的两个⽅法,如果没有找到指定元素就返回-1
8,Sort()对列表中是元素进⾏从⼩到⼤排序
索引器:通过[index]这种形式去访问数据,就是索引器
MyList
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyList
{
//首先,对于集合类来说,不知道会存储什么数据,所以要使用泛型
class MyList<T>
{
//定义数组 存储数据
private T[] data = new T[0];
//引用类型赋值 new 否则就是null 空引用 不能调用任何成员
private int count = 0;//元素个数 数据个数
//获取到元素个数
public int Count
{
get
{
return count;
}
}
//声明一个容量属性
public int Capacity
{
get//获取当前容量
{
return data.Length;
}
}
public void Add(T item)
{
//先判断数组长度是否为0
if (data.Length == 0)
{
data = new T[4];//如果等于0,就把data长度改成4
}
//添加元素之前,先判断数组是否已经满
//扩充数组的代码
if (data.Length == count)
{
T[] temp = new T[count * 2];//声明一个容量是原本两倍的临时数组
//把原本的数据拿到temp里面
for (int i = 0; i < data.Length; i++)
{
temp[i] = data[i];//遍历,然后把遍历的数据给到新的数组
}
data = temp;
}
//添加新数据的时候就添加到与count数据相同位置的索引
data[count] = item;
count++;
}
//索引器
public T this[int index]
{
get
{
if (index < 0 || index > count - 1)
{
throw new ArgumentOutOfRangeException("索引参数超出了范围");
}
return data[index];
}
set
{
data[index] = value;
}
}
//插入数据
public void Insert(int index, T item)
{
//判断索引是否在数据范围内
if (index < 0 || index > count - 1)
{
throw new ArgumentOutOfRangeException("索引参数超出了范围");
}
//从后往前遍历,完成数据的迁移
for (int i = count - 1; i > index - 1; i--)
{
data[i + 1] = data[i];
}
data[index] = item;
count++;
}
//添加移除方法
public void RemoveAt(int index)
{
if (index < 0 || index > count - 1)
{
throw new ArgumentOutOfRangeException("索引参数超出了范围");
}
//把index之后的数据向前移动
for(int i = index + 1; i < count; i++)//从index+1一直遍历到count-1
{
data[i - 1] = data[i];
}
count--;
}
//索引方法
//遍历所有的数据,然后判断item的位置
public int IndexOf(T item)
{
int index = -1;
for(int i = 0; i < count; i++)
{
if (item.Equals(data[i]))//Equals判断两个对象是否相等的方法
{
index = i;break;
}
}
return index;
}
//从后面遍历的方法
public int LastIndexOf(T item)
{
int index = -1;
for (int i = count-1; i >=0; i--)
{
if (item.Equals(data[i]))//Equals判断两个对象是否相等的方法
{
index = i; break;
}
}
return index;
}
//排序方法
public void Sort()
{
Array.Sort(data, 0, count);
}
}
}
Main
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyList
{
class Program
{
static void Main(string[] args)
{
MyList<int> list = new MyList<int>();
//Console.WriteLine(list.Capacity);
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
//Console.WriteLine(list.Count);//获取到元素个数\
//获取到所有值
//for (int i=0; i < list.Count; i++)
//{
// Console.Write(list[i] + " ");
//}
极端情况 超出最大索引和小于最小索引
//int temp1 = list[100];
//int temp2 = list[-1];//异常报错
//使用系统的集合类去创建对象
//List<int> l = new List<int>();
//int temp = l[-1];//报错
//插入数据测试
list.Insert(2, 100);
for (int i = 0; i < list.Count; i++)
{
Console.Write(list[i] + " ");//1 2 100 3 4 5
}
Console.WriteLine();//换行
//测试移除功能
list.RemoveAt(3);
for (int i = 0; i < list.Count; i++)
{
Console.Write(list[i] + " ");//1 2 100 4 5
}
Console.WriteLine();//换行
//查找索引测试
Console.WriteLine(list.IndexOf(100));//2
//反向索引测试
Console.WriteLine(list.LastIndexOf(100));//2
//排序测试
list.Sort();
list.Insert(2, 100);
for (int i = 0; i < list.Count; i++)
{
Console.Write(list[i] + " ");//1 2 100 4 5 100
}
Console.WriteLine();//换行
}
}
}
通过索引器获得数据
开发SortRemoveAt和IndexOf方法-完成列表开发
Equals方法-课程完结
Equals示范
//Equals
//Equals ToString 都是位于基类Obje里
int a = 12;
int b = 34;
Console.WriteLine(a.Equals(b));//False
string str1 = "546sda";
string str2 = "553sd";
Console.WriteLine(str1.Equals(str2));//False
在引用类型中的使用
一个普通类
//普通类
private int age;
private string name;
public Student(int age, string name)
{
this.age = age;
this.name = name;
}
使用
Student s1 = new Student(18, "小芳");
Student s2 = new Student(18, "小芳");
Console.WriteLine(s1.Equals(s2));//False 数据一样却False 因为比较的是引用地址而不是数据
解决方法:重写
//重写Equals方法,让它比较数据
public override bool Equals(object obj)
{
//先转换成Student类
Student stu = (Student)obj;//强赛
if (age == stu.age && name == stu.name)
{
return true;
}
return false;
}
再次比较使用
Student s1 = new Student(18, "小芳");
Student s2 = new Student(18, "小芳");
Console.WriteLine(s1.Equals(s2));//True 这次是比较了数据
调用了重写过的方法
Student(int age, string name)
{
this.age = age;
this.name = name;
}
使用
```C#
Student s1 = new Student(18, "小芳");
Student s2 = new Student(18, "小芳");
Console.WriteLine(s1.Equals(s2));//False 数据一样却False 因为比较的是引用地址而不是数据
解决方法:重写
//重写Equals方法,让它比较数据
public override bool Equals(object obj)
{
//先转换成Student类
Student stu = (Student)obj;//强赛
if (age == stu.age && name == stu.name)
{
return true;
}
return false;
}
再次比较使用
Student s1 = new Student(18, "小芳");
Student s2 = new Student(18, "小芳");
Console.WriteLine(s1.Equals(s2));//True 这次是比较了数据
调用了重写过的方法
总之 任何类型都可以用Equals作比较,但是不是所有类型都能用==作比较