当前位置: 首页 > news >正文

C#`Array`进阶

一、数组方法进阶(Array类核心方法解析)

该部分主要介绍Array类的静态方法与实例方法,核心是高阶函数(参数为函数的方法)的应用,通过回调函数实现灵活的数组查询与操作。

1. 核心静态方法(Array.XXX

静态方法需通过Array类直接调用,主要用于数组查询、判断、遍历等,参数常包含 “回调函数”(定义查询条件)。

方法作用关键参数示例场景
Find从前向后查找第一个满足条件的元素数组 + 回调函数(返回bool,表示元素是否符合条件)查找第一个不满 18 岁的年龄(Array.Find(ages, FindSamll18)
FindLast从后向前查找第一个满足条件的元素Find查找最后一个能被 3 和 5 整除的数(Array.FindLast(ages, Find35)
FindIndex从前向后查找第一个满足条件的元素的索引Find查找第一个能被 3 和 5 整除的数的索引(Array.FindIndex(ages, Find35)
FindLastIndex从后向前查找第一个满足条件的元素的索引Find查找最后一个能被 3 和 5 整除的数的索引(Array.FindLastIndex(ages, Find35)
TrueForAll判断数组所有元素是否都满足条件(全满足返回true数组 + 回调函数判断所有数字是否都是偶数(Array.TrueForAll(nums, FindEven)
Exists判断数组至少有一个元素满足条件(有一个满足返回true数组 + 回调函数判断是否存在偶数(Array.Exists(nums, FindEven)
ForEach遍历数组,对每个元素执行指定操作(替代for/foreach的专用遍历)数组 + 回调函数(无返回值,执行操作)遍历数组并对每个元素 + 1 输出(Array.ForEach(nums, Each)
2. 实例方法(数组对象.XXX)

实例方法通过数组对象调用,主要用于数组复制、元素操作、属性查询等。

方法作用示例
CopyTo将当前数组元素复制到目标数组的指定位置str1.CopyTo(str2, 1)(将str1str2[1]开始复制)
GetLength获取多维数组指定维度的长度(一维数组等效于Lengthstr1.GetLength(0)(返回一维数组str1的长度)
GetValue/SetValue获取 / 设置指定索引的元素值str1.GetValue(0)(获取str1[0]);str1.SetValue("郑爽", 1)(设置str1[1]
Contains判断数组是否包含指定元素(需引入System.Linqstr1.Contains("李云迪")(判断是否包含 “李云迪”)
3. 代码核心分析
  • 高阶函数与回调函数Find/TrueForAll等方法的第二个参数是 “回调函数”(如FindSamll18),这些方法内部会循环数组,将每个元素传入回调函数,根据返回值判断是否满足条件。这种设计让数组操作更灵活(同一方法可通过不同回调实现不同查询)。

  • 示例逻辑: 例如Array.Find(ages, FindSamll18)的执行流程:循环ages数组,每次将元素传入FindSamll18,若返回true(元素 < 18),则立即返回该元素。 代码中FindSamll18/FindOdd等回调函数,本质是将 “查询条件” 封装为可复用的逻辑。

二、Lambda 表达式(匿名函数的简化语法)

Lambda 表达式是匿名函数的语法糖,用于简化回调函数的定义,尤其在高阶函数中可大幅减少代码量。

1. 语法演进(从完整到简写)

Lambda 的核心是=>(Lambda 运算符,读作 “goes to”),左侧为参数,右侧为函数体。语法逐步简化如下:

形式示例代码说明
完整形式Func<int, int, int> fn1 = (int a, int b) => { return a + b; };显式指定参数类型,函数体用{}包裹,包含return
省略参数类型Func<int, int, int> fn2 = (a, b) => { return a + b; };编译器自动推断参数类型(基于委托类型Func<int, int, int>
单个参数省略括号Func<int, int> fn3 = a => { return a + 13; };仅一个参数时,可省略()
单表达式省略{}returnFunc<int, int> fn4 = a => a + 13;函数体仅一个表达式时,自动返回表达式结果,无需{}return
2. 在数组方法中的应用

Lambda 表达式最常用的场景是替代命名回调函数,让代码更紧凑。例如:

命名函数方式Lambda 表达式方式说明
Array.Find(ints, FindEven)Array.Find(ints, v => v % 2 == 0)用 Lambda 直接定义 “偶数条件”,替代单独定义的FindEven函数
Array.FindIndex(strings, FindLength2)Array.FindIndex(strings, v => v.Length == 2)直接在参数中定义 “长度为 2” 的条件,无需额外函数
3. 核心优势
  • 简化代码:省去命名函数的定义,将条件逻辑直接写在调用处,减少跳转。

  • 增强可读性:查询条件与方法调用在同一位置,逻辑更连贯(如v => v.StartsWith("吴")直观表示 “以吴开头”)。

  • 灵活适配:针对一次性使用的简单条件,无需定义复用函数,降低冗余。

三、数组排序(冒泡排序、选择排序与Array.Sort

排序是数组操作的核心场景,这里介绍两种基础排序算法及Array.Sort的用法。

1. 冒泡排序

原理:通过相邻元素的比较与交换,使最大元素逐步 “冒泡” 到数组尾部,重复缩小范围直至排序完成。

  • 核心代码(优化版):

    int[] ints1 = { 1, 8, 6, 2, 5, 4, 10, 3 };
    for (int i = 0; i < ints1.Length; i++)
    {// 内层循环范围:0 ~ 长度-1-i(排除已排序的尾部元素)for (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]); // 交换元素}}
    }

  • 优化点:内层循环j < ints1.Length - 1 - i,每次排除已排序的尾部元素(减少无效比较)。

  • 时间复杂度:O (n²)(适合小规模数据)。

2. 选择排序

原理:每次从剩余元素中找到最小值,与未排序部分的首个元素交换,逐步构建有序序列。

  • 核心代码:

    for (int i = 0; i < ints1.Length; i++)
    {int minIndex = i; // 记录最小值索引for (int j = i + 1; j < ints1.Length; j++){if (ints1[j] < ints1[minIndex]) minIndex = j; // 更新最小值索引}if (minIndex != i) // 交换最小值到当前位置{(ints1[i], ints1[minIndex]) = (ints1[minIndex], ints1[i]);}
    }

  • 优势:交换次数少(每次外层循环仅交换 1 次),比冒泡排序略高效。

  • 时间复杂度:O (n²)(同样适合小规模数据)。

3. Array.Sort(内置排序)

C# 提供Array.Sort静态方法,默认升序,支持通过 Lambda 自定义排序规则。

  • 基础用法:

    int[] ints = { 3, 1, 4, 2 };
    Array.Sort(ints); // 默认升序:[1, 2, 3, 4]
  • 自定义排序(Lambda 比较器):

    // 升序:a - b(返回负数时a在前,正数时b在前)
    Array.Sort(ints, (a, b) => a - b); 
    // 降序:b - a
    Array.Sort(ints, (a, b) => b - a); 
  • 比较器逻辑:Lambda 返回值决定元素顺序 —— 负数(a 在前)、正数(b 在前)、0(位置不变)。

4. 排序算法对比
维度冒泡排序选择排序Array.Sort(内置)
时间复杂度O(n²)O(n²)O (n log n)(快排 / 混合排序)
交换次数多(每次比较可能交换)少(每次外层循环最多交换 1 次)内部优化,效率高
适应性可优化(检测到有序时提前终止)不可(固定遍历次数)自动适配数据规模
适用场景小规模数据、教学演示小规模数据、交换成本高的场景实际开发(高效、简洁)

四、作业实现与分析(People数组查询)

基于People数组的 5 个查询需求,结合前面的数组方法与 Lambda 表达式实现,分析如下:

1. 定义People类与数组
class People
{public enum ESex { man, woman } // 性别枚举public string Name { get; set; } // 姓名public int Age { get; set; } // 年龄public ESex Sex { get; set; } // 性别
}
​
// 初始化数组
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 }
};
2. 需求实现与分析
需求实现代码核心方法 / 逻辑
1. 查询所有男性var allMen = peoples.Where(p => p.Sex == People.ESex.man).ToList();Where(LINQ 方法):筛选所有满足 “性别为男性” 的元素,返回IEnumerable<People>,通过ToList()转为列表。
2. 查询第一个女性var firstWoman = Array.Find(peoples, p => p.Sex == People.ESex.woman);Array.Find:从前向后查找第一个 “性别为女性” 的元素。
3. 判断是否全为成年人(≥18)bool allAdults = Array.TrueForAll(peoples, p => p.Age >= 18);TrueForAll:检查所有元素是否满足 “年龄≥18”,因权志龙 8 岁,返回false
4. 计算年龄平均值double avgAge = peoples.Average(p => p.Age);Average(LINQ 方法):计算所有元素 “Age” 属性的平均值,结果为(18+22+21+32+8+18)/6 ≈ 19.83
5. 查询第一个未成年男性(<18)var firstMinorMan = Array.Find(peoples, p => p.Sex == People.ESex.man && p.Age < 18);Array.Find:筛选 “男性且年龄 < 18” 的第一个元素(权志龙)。
3. 关键方法选择依据
  • 批量查询(所有男性):用Where(返回所有满足条件的元素)。

  • 单个元素查询(第一个女性 / 未成年男性):用Array.Find(高效返回首个匹配元素)。

  • 全量判断(是否全为成年人):用TrueForAll(一次性验证所有元素)。

  • 数值计算(平均年龄):用Average(LINQ 提供的聚合方法,简化计算)。

http://www.lryc.cn/news/592286.html

相关文章:

  • ChatGPT Agent技术架构探析
  • 力扣面试150(33/150)
  • 解决 IDEA 中 XML 文件的 “URI is not registered” 报错
  • 优先算法——专题九:链表
  • Logback 配置的利器:深入理解<property>与<variable>
  • 深度解析Linux文件I/O三级缓冲体系:用户缓冲区→标准I/O→内核页缓存
  • 【C语言】深入理解柔性数组:特点、使用与优势分析
  • MySQL安装包安装方法
  • Vue (Official) v3.0.2 新特性 为非类npm环境引入 globalTypesPath 选项
  • 28、鸿蒙Harmony Next开发:不依赖UI组件的全局气泡提示 (openPopup)和不依赖UI组件的全局菜单 (openMenu)、Toast
  • ModbusRTU转profibus网关与涡街液体流量计通讯读取流量计温度
  • 回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测
  • jvm分析篇---1、先认识下dump文件
  • Kubernetes Pod 深度理解
  • 【C语言进阶】题目练习(2)
  • Composer 可以通过指定 PHP 版本运行
  • uni-app 跳转外部连接
  • 网络原理——UDP
  • 如何 ASP.NET Core 中使用 WebSocket
  • html复习
  • 【收集电脑信息】collect_info.sh
  • 电脑插上u盘不显示怎么回事
  • 分表聚合助手类
  • 分布式面试点
  • RecyclerView与ListView深度对比分析
  • 从复合变量到分组分析:piecewiseSEM 解析生态系统多因子交互作用
  • UDP 协议下一发一收通信程序的实现与解析
  • Linux 定时任务全解析:atd 与 crond 的区别及实战案例(含日志备份 + 时间写入)
  • AugmentCode还没对个人开放?
  • 双通达信多板块同步