文章目录
- 数组操作与高阶方法
- Lambda表达式
- Lambda表达式在C#中的应用及练习
- 数组排序:深入理解冒泡排序与选择排序
- 冒泡排序
- 原理
- 选择排序
- 原理
- 选择排序和冒泡排序的区别
- C#排序:掌握Sort()方法的使用
- 集合类型全览:C#集合的使用详解
- C# 中的集合类型
- C# ArrayList:动态数组
- 动态类型编程:var与dynamic的对比
- C# List:泛型集合
- 上期习题答案
- 本期习题
数组操作与高阶方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;namespace _01.数组的方法_进阶_
{internal class Program{static void Main(string[] args){//上期常见基础方法//Array.Clear();//Array.Copy();//Array.Reverse();//Array.IndexOf();int[] ints = { 13, 53434, 15, 34, 32 };//需求:查询数组中第一个年龄为18的索引 indexOf();//如果需要对数组中的数据,进行范围查询,indexOf()无法满足需求//比如: 查询数组中第一个不满足18的数字//根据传入的数组和方法,从前往后查询,返回第一个满足条件的数据//Find工作原理:循环该数组,并且每次循环调用传递的方法,并且//将当前数据通过参数传递到方法中,如果方法返回true,则Find直接返回当前参数//参数1查询的数组//参数2一个函数,这个函数应该返回一个布尔值,表示当前数值是否满足条件//如果数组中没有满足条件的数组,则返回该类型数据的默认值Console.WriteLine(Array.Find(ints,FindSmall18)); //返回数组中第一个奇数Console.WriteLine(Array.Find(ints,FindOdd)); //Odd为奇数//返回数组中既能被3整除又能被5整除的数 Console.WriteLine(Array.Find(ints, Find35));string[] str = { "132", "4235252", "3245356" };//FindIndex用法和Find相同,从前往后查询,返回第一个满足条件的索引//如果都不满足条件则返回-1Console.WriteLine(Array.FindIndex(str,Find3)); //FindLastIndex,从后往前查询,返回第一个满足条件的数据索引//如果都不满足条件则返回-1Console.WriteLine(Array.FindLastIndex(ints, FindSmall18));//FindLast,从后往前查询,返回第一个满足条件的数据//如果都不满足条件则返回-1Console.WriteLine(Array.FindLast(ints, FindSmall18));//FindLastIndex,从后往前查询,返回第一个满足条件的数据的索引//如果都不满足条件则返回-1Console.WriteLine(Array.FindLastIndex(ints, Find35));int[] arr = { 12, 345, 32, 435, 1, 123 };//FindAll 查询所有满足条件的数据,返回的是一个数组int[]ints2=Array.FindAll(ints,FindSmall18);//TrueForAll判断数组中的数据是否全部都满足条件,全部满足返回true有一个不满足返回falseArray.TrueForAll(arr,FindOdd);//Exists判断数组中的数据是否有一个满足条件,有一个满足返回true,所有都不满足则返回falseArray.Exists(arr,Find35);//用于循环数组Array.ForEach(arr, Each);//以上这些方法 都是Array类上的方法,,需要使用Array.xxx调用//-----------------------------------------------------------------------//以下这些方法 都是Array实例上的方法,需要使用 数组.xxx调用string[] str1 = { "吴凡", "罗祥", "李迪" };string[] str2 = new string[5];//将str1复制到str2中,从str2的索引为1的位置开始放str1.CopyTo(str2, 1);//["null","吴凡", "罗祥", "李迪","null"]int[,,] ints1 = new int[10, 3, 4];Console.WriteLine(str1.GetLength(0));Console.WriteLine(str1.GetLength(1));Console.WriteLine(str1.GetLongLength(1));//等同于 str1[1]="权龙"str1.SetValue("权龙", 1);//等同于 str1[2]Console.WriteLine(str1.GetValue(2, 7, 7));Console.WriteLine(str1.Contains("吴凡"));//str1.All() 等同于 Array.TrueForAll();//str1.Any() 等同于 Array.Exists();}public delegate bool DFind35(int value);public static int Find(int[] ints, DFind35 de){for (int i = 0; i < ints.Length; i++){if (de(ints[i]))return ints[i];}return 0;}public static bool FindSmall18(int value){//if (value < 18) return true;//else return false;//因为逻辑运算符返回就是一个布尔值,所以可简化return value < 18;}public static bool FindOdd(int value){return value % 2 != 0;}public static bool Find35(int value){return value % 3 == 0&&value % 5 == 0;}public static bool Find3(string value){return value.Length < 2;}public static void Each(int value){Console.WriteLine(value);}}
}
Lambda表达式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _03_lambda表达式
{internal class Program{static void Main(string[] args){//具名函数//Lambda表达式本质上就是匿名函数(没有名字的函数)Write();//如果代码块内部和外部有同名的方法,调用内部的方法//函数不仅可以定义在类中,也可以定义在代码块中//格式://返回值类型 函数名(形参){函数内容}void Write(){for (int i = 0; i < 10; i++){Console.WriteLine("罗祥");}}//需求:定义函数,求两个数的和int Sum(int a,int b){return a + b;}Console.WriteLine(Sum(10, 1));//int[] ints = { 1, 2, 3, 4, 5 };查找数组中第一个偶数//Array.Find(ints,FindEven);//bool FindEven(int v)//{// return v%2 == 0;//}//Lambda表达式 用于创建一个函数//格式:Func<参数1的类型,参数2的类型,返回值类型>fnName(参数1,参数2)=>{函数的内容}Func<int, int, bool> fnName1 = (int a, int b) =>{return a > b;};//调用的时候和普通的函数相同Console.WriteLine(fnName1(19,10));//lambda表达式的声明可以简化//1.函数的实现中,参数的类型可以省略Func<int, int, bool> fnName2 = (a,b) =>{return a > b;};//2.如果只有一个参数,可以省略()Func<int, bool> fnName3 = a =>{return a %2==0;};//3.如果函数中只有一个表达式,,可以省略{}和return,他会自动返回表达式的运行结果Func<int, bool> fnName4 = a => a % 2 == 0;//如下代码和53代码等价Func<int, int, bool> fnName5 = (a, b) => a > b;int[] ints = { 1, 2, 3, 4, 5 };//查找数组中第一个偶数Console.WriteLine(Array.Find(ints, v => v % 2 == 0));//bool FindEven(int v)//{// return v % 2 == 0;//}//Func<int, bool> FindEven = (v) =>//{// return v % 2 == 0;//};int[] ages = { 19, 32, 31, 16, 24, 15 };//查询数组中第一个不满足18的数字Console.WriteLine(Array.Find(ages,v => v < 18));}public static void Write(){for (int i = 0; i < 10; i++){Console.WriteLine("吴凡");}}}
}
Lambda表达式在C#中的应用及练习
答案在下期
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _04_练习
{internal class Program{static void Main(string[] args){People[] peoples ={new People {Name="吴亦凡",Age=18,Sex=People.ESex.man},new People {Name="郑爽",Age=22,Sex=People.ESex.woman},new People {Name="李云迪",Age=21,Sex=People.ESex.man},new People {Name="蔡徐坤",Age=32,Sex=People.ESex.man},new People {Name="权志龙",Age=8,Sex=People.ESex.man},new People {Name="杨幂",Age=18,Sex=People.ESex.woman}};//1.查询peoples中所有的男性//2.查询peoples中第一个女性//3.判断数组中是否全部都是成年人//4.计算所有人的年龄的平均值//5.查询所有人中第一个未成年的男性}}class People{public enum ESex{man,woman}public string Name { get; set; }public int Age { get; set; }public ESex Sex { get; set; }}
}
数组排序:深入理解冒泡排序与选择排序
冒泡排序
冒泡排序,Bubble Sort 一个简单且常用的排序算法。因最大或最小的元素会经过交换慢慢出现在数列顶端,好似元素冒出来一样,得名“冒泡排序”。
原理
1.比较相邻的元素,若第一个比第二个大则交换他们两个。
2.对每一组相邻的元素做同样的工作(从开始的第一对到最后的最后一对)。
3.针对除最后一个元素外的所有元素重复以上的步骤。
4.重复对未定位到合适位置的元素操作上述步骤直至排序完成。
//冒泡排序//将数组中每一位都和相邻的另一位进行对比,如果右边的更小,则进行交换int[] ints1 = { 6, 5, 4, 3, 2, 1 };外层循环执行一次 内层循环执行全部 外层循环执行 6 内层循环 56*5 需要30次才能把数组排序好//for (int i = 0; i < ints1.Length; i++)//{// //-1的原因: 如果最后不-1 最后一次循环 ints1[5] ==1 ints1[5+1] 索引越界// for (int j = 0; j < ints1.Length-1; j++)// {// //相邻的元素进行比较,如果前一个值比后一个值大,交换位置// if (ints1[j] > ints1[j+1])// {// //不使用语法糖 交换两个变量的位置// int temp = ints1[j];// ints1[j]= ints1[j+1];// ints1[j+1]= temp;// }// }//}//--------------------优化--------------------for (int i = 0; i < ints1.Length; i++){//-i的原因: 减去已经排序好的数字,外层循环一次,就多了一个排序好的数字//ints1.Length-1-i 让内层循环每一次循环少少一次//5+4+3+2+1=15for (int j = 0; j < ints1.Length - 1-i; j++){if (ints1[j] > ints1[j + 1]){(ints1[j], ints1[j + 1]) = (ints1[j + 1], ints1[j]);}}}
选择排序
选择排序在要排序的一组数中,选出最小(或最大)的一个数与第一个位置的数交换;在剩下的数当中找最小的与第二个位置的数交换,即顺序放在已排好序的数列的最后,如此循环,直到全部数据元素排完为止
原理
- 先从数组中选出一个最小的元素,将其与数组首元素交换位置
- 从剩下的n-1个元素中选出最小的元素,将其与数组的第二个元素交换位置
- 从剩下的n-2个元素中选出最小的元素,将其与数组的第三个元素交换位置
- 以此类推,直到剩下的元素个数为0
int[] ints1 = { 6, 5, 4, 3, 2, 1 };for (int i = 0; i <ints1.Length; i++){//找到最小值的索引int minNumPost = FindMinPos(ints1,i);//交换i和最小值(ints1[i], ints1[minNumPost]) = (ints1[minNumPost], ints1[i]);}public static int FindMinPos(int[] arr,int startIndex){//假定一个最小值, 默认值为无穷double minNum = double.PositiveInfinity;//记录最小值的索引位置int minIndex = -1;for (int i = startIndex; i < arr.Length; i++){if (arr[i]<minNum){minNum = arr[i];minIndex = i;}}return minIndex;}
选择排序和冒泡排序的区别
- 冒泡排序将最大的元素逐渐后移,选择排序将最大的元素直接右移
- 每次循环时,冒泡排序会将大的元素逐渐后移,选择排序只会将最大的元素直接右移
- 排序后,冒泡排序不会改变相同元素的相对次序,选择排序会改变
C#排序:掌握Sort()方法的使用
int[] ints2 = { 6, 5, 7, 8, 3, 4, 2 };//Array类有一个Sort方法,用于数组的排序,(默认是正序(升序)排列)//升序:从小到大//降序:从大到小// Array.Sort(ints2);//Array.Reverse(ints2);//Array.Sort(ints2, (x, y) =>//{//如果小于 0 则x小于y//如果为0 则x等于y//如果大于 0 则x大于y//升序//if (x < y) return -1;//if (x > y) return 1;//return 0;//如果需要倒序排列 则反向返回即可//if (x < y) return 10000;//if (x > y) return -10000;//return 0;//return x - y;//正序// return y - x;//倒序//});//拓展了解: 二分法//升序排列Array.Sort(ints2,(x,y)=>x-y);//降序排列Array.Sort(ints2, (x, y) => y - x);
集合类型全览:C#集合的使用详解
C# 中的集合类(Collection)是专门用于数据存储和检索的类,类中提供了对栈(stack)、队列(queue)、列表(list)和哈希表(hash table)的支持。大多数集合类都实现了相同的接口。
集合类的用途多种多样,例如可以动态的为元素分配内存、根据索引访问列表项等等,这些类创建 Object 类的对象集合,Object 类是 C# 中所有数据类型的基类。
C# 中的集合类型
在 System.Collections.Generic,System.Collections.Concurrent 和 System.Collections 命名空间下提供了许多集合类型,每种集合类型都有特定的用途,下面以 System.Collection 命名空间为例,该命名空间下提供的集合类型如下表所示:
类 | 描述和用法 |
---|---|
动态数组(ArrayList) | 不固定长度和存储的数据类型的数组,可以存储任意类型的数据,并且长度会随着数据内容的增加减少进行改变 |
泛型集合(List) | 类似ArrayList,只是List只能存储相同类型的数据,List的长度也不是固定的 |
字典(Dictionary) | 类似List.只能存储固定类型的数据,长度不固定 |
哈希表(Hashtable) | 哈希表可以使用键来访问集合中的元素。 哈希表中的每一项都由一个键/值对组成,键用于访问集合中的指定项。 |
排序列表(SortedList) | 排序列表是数组和哈希表的组合,可以使用键或索引来访问列表中的各项。 排序列表中包含一个可使用键或索引访问各项的列表,如果您使用索引访问各项,则它是一个动态数组,如果您使用键访问各项,则它就是一个哈希表。 另外,排序列表中的各项总是按键值进行排序的。 |
堆栈(Stack) | 堆栈代表了一个后进先出的对象集合。 当您需要对各项进行后进先出的访问时,则可以使用堆栈。为堆栈中添加一项称为推入项目,从堆栈中移除一项称为弹出项目。 |
队列(Queue) | 队列代表了一个先进先出的对象集合。 当您需要对各项进行先进先出的访问时,则可以使用队列。为队列中添加项目称为入队,为队列中移除项目称为出队。 |
C# ArrayList:动态数组
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _06_ArrayList
{internal class Program{static void Main(string[] args){//动态数组(一个集合),就是不固定长度和存储的数据类型的数组//可以存储任意类型的数据,并且长度会随着数据内容的增加减少进行改变//普通的数组的创建int[] array1 = new int[10];int[] array2 = { 1, 2, 34, 4, 5, 5 };//赋值array1[0] = 999;//动态数组的创建ArrayList list1=new ArrayList();ArrayList list2=new ArrayList() { "吴凡","李峰",1,true,new int[] {1} };//普通的数组获取数组的长度Console.WriteLine(array2.Length);//动态数组获取数组的长度Console.WriteLine(list2.Count);//普通数组设置值array2[0] = 9999;//普通数组获取值Console.WriteLine(array2[0]);//动态数组设置值list2[0] = "凡凡";//动态数组获取值Console.WriteLine(list2[0]);//--------------------------------------//动态数组的方法//1.Add() 向ArrayList的最后的位置添加数据list2.Add("李迪"); //{ "吴凡","李峰",1,true,new int[] {1},"李迪" }int[] ints1 = { 666, 777, 888 }; //数组也是一个集合//2.AddRange() 将另一个集合的内容添加到ArrayList的尾部list2.AddRange(ints1); //{ "吴凡","李峰",1,true,new int[] {1},"李迪", 666, 777, 888 }ArrayList arrayList=new ArrayList() { "加拿大劣迹男艺人吴凡","时间管理大师罗祥"};list2.AddRange(arrayList); //{ "吴凡","李峰",1,true,new int[] {1},"李迪", 666, 777, 888 ,"加拿大劣迹男艺人吴凡","时间管理大师罗祥"}//3.Clear() 清空数组,删除动态数组中所有的数据,并将Count重置为0list2.Clear();list2.Add("吴凡");list2.Add("罗祥");//4.Insert() 在指定的索引位置插入数据list2.Insert(1, "凡凡"); //{"吴凡","凡凡","罗祥"}//5.InsertRange() 在指定的索引位置插入集合的内容list2.InsertRange(2, ints1); //{"吴凡","凡凡",666, 777, 888 "罗祥"}//6.Contains() 判断动态数组中是否存储指定数据Console.WriteLine(list2.Contains("吴凡"));//7.GetRange()从数组中截取对应的数据,返回新的ArrayList//参数1:开始截取的索引位置//参数2:截取的个数ArrayList list3 = list2.GetRange(1, 3);//8. IndexOf() Console.WriteLine(list2.IndexOf("罗祥"));//9.Remove() 删除动态数组中指定的第一个数据list2.Remove("罗祥");//10.RemoveAt() 删除指定索引位置的数据list2.RemoveAt(1);//11.RemoveRange() 删除指定范围的数据 从1开始删除 删除2个list2.RemoveRange(1,2);//12.Reverse() 反转动态数组list3.Reverse();//13.Sort() 排序动态数组list3.Sort();//14.SetRange() 将参数2集合中的数据复制到当前动态数组中,//参数1 指定从动态数组中第几个索引位置开始放list3.SetRange(1,ints1);}
}
动态类型编程:var与dynamic的对比
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _07_var
{internal class Program{static void Main(string[] args){int a = 1;double b = 1.2;string c = "字符串";//var声明变量var d = 4;var e = "字符串";d = 5;e = "凡凡";Console.WriteLine(e.Split(','));//e = 66;//使用var 声明的变量 不是var类型(var 不是数据类型),而是由编译器自动根据变量的初始值进行变量类型的推断dynamic s1 = "字符串";// s1 = 44;Console.WriteLine(s1.Split(','));//dynamic 虽然也可以定义任意类型的变量,但是他是弱类型的//1.dynamic类型的变量就是dynamic类型,var声明的变量是初始值类型//2.dynamic 声明的变量,在编译期间不会提示//3.dynamic声明的变量如果进行非该类型的操作时,将会在运行期间保存,var声明的变量在编译期间就会报错int aa;aa = 1;//注意:var 声明的变量,必须指定初始值,否则会报错//var bb;//var 的使用场景:ArrayList array = new ArrayList() { 1, "1", true };//1.用于foreach循环中foreach (var v in array){Console.WriteLine(v);}//2.用于接收方法的返回值var n = Test();}public static string[] Test(){return new string[] {"1"};}}
}
C# List:泛型集合
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace _08_List
{internal class Program{static void Main(string[] args){//List也是一个集合,类似ArrayList,只是List只能存储相同类型的数据,List的长度也不是固定的//格式:List<数据类型> 变量名 =new List<数据类型>();List<int> list=new List<int>() { 1,234,4,5,66,7};List<string>list2 = new List<string>();//List是强类型的,只能存储一个类型的数据,因此在查询,添加,替换的时候,免去了转换的过程,速度更快,代码更健壮//List也是通过索引进行数据的分配,索引和数组相同,从0开始//设置值//list.Add(999);//list[0] = 999;Console.WriteLine(list[0]);//获取值Console.WriteLine(list.Count);//长度//微软官方API文档//https://learn.microsoft.com/zh-cn/dotnet/api/system.collections.generic.list-1?view=net-7.0list.Add(66);list.Remove(0);//删除所有满足条件的list.RemoveAll(v => v > 4);list.RemoveAt(1);list.AddRange(new int[] {55,666,777});list.Sort();list.Reverse();list.Insert(1,999);list.IndexOf(1);//.... 基本上数组支持的方法 List都支持//List的遍历for (int i = 0; i < list.Count; i++){Console.WriteLine(list[i]);}foreach (int v in list){Console.WriteLine(v);}}}
}
集合类型未完,下期继续
上期习题答案
- 定义一个数组,再逆序存储它的值 (自定义Reverse) 如 int[] a = new int[] { 1,9,3,4 };
经过一系列操作后将数组变成: {4,3,9,1}
static public void Reverse(int[] arr){//逆序数组,只需要循环数组的一半,交换当前位置和后面对应的位置的数据即可for (int i = 0; i < arr.Length / 2; i++){//i==0 // (1,6) =(6,1)//i==1// (2,5) = (5,2)(arr[i], arr[arr.Length - i - 1]) = (arr[arr.Length - i - 1], arr[i]);}
- 定义一个长度为 50 的数组,数组里面的值是从 0~99 随机产生的,找出30出现的次数
int[] ints1 = new int[50];Random random = new Random();for (int i = 0; i < ints1.Length; i++){// Console.WriteLine(random.Next(0,100));ints1[i] = random.Next(0, 100);}FindNumCount(ints1,30);
- 实现一个方法用于打乱一个数组
static public void Luan(int[] arr){Random random = new Random();for (int i = 0; i < arr.Length; i++){int indexRandom = random.Next(0, arr.Length);(arr[i], arr[indexRandom]) = (arr[indexRandom], arr[i]);}
- 将数组中的数据排序 (冒泡排序,选择排序)
- 冒泡排序
int ints3={123,534,12,43}for (int i = 0; i < ints3.Length; i++){//-1的原因: 如果最后不-1 最后一次循环 ints1[5] ==1 ints1[5+1] 索引越界//-i的原因: 减去已经排序好的数字,外层循环一次,就多了一个排序好的数字for (int j = 0; j < ints3.Length - i - 1; j++){if (ints3[j] > ints3[j + 1]){(ints3[j], ints3[j + 1]) = (ints3[j + 1], ints3[j]);}}}
- 选择排序
int[] ints5 = { 213, 434, 12, 4531, 2 };for (int i = 0; i < ints5.Length; i++){for (int j = i; j < ints5.Length; j++){if (ints5[i] > ints5[j]){(ints5[i], ints5[j]) = (ints5[j], ints5[i]);}}}
本期习题
-
创建一个集合 往集合中添加一些数字 求平均值
-
创建一个集合 长度为10 在里面随机存放十个数字(0 - 9),并且这十个数不可以重复
-
将一个数组中的奇数放到一个集合,偶数放到一个集合,然后将奇数集合在左边输出 偶数集合在右边输出
int[] num = new int[] { 1, 3, 5, 6, 8, 100, 20, 11 };
-
提示用户输入一个字符串,通过foreach循环将用户输入的字符串赋值给一个字符数组
-
删除数组中重复的值
string[] stringArray = { “aaa”, “bbb”, “aaa”, “ccc”, “bbb”, “ddd”, “ccc”, “aaa”, “bbb”, “ddd” };