入门学习 - 列表List,泛型

文章详细介绍了C#中的列表(List)的创建、初始化、添加元素、遍历、访问、删除以及排序等操作。特别强调了列表与数组的区别,列表的动态扩容机制,以及如何通过泛型实现对不同类型数据的操作。还展示了如何创建自定义的MyList集合类,实现类似List的功能,包括Capacity、Add、Insert、索引访问、RemoveAt、IndexOf等方法。
摘要由CSDN通过智能技术生成

什么是列表和列表的创建添加遍历访问

什么是列表和列表的创建添加遍历访问

集合类 列表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作比较,但是不是所有类型都能用==作比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值