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 获取多维数组指定维度的长度(一维数组等效于Length str1.GetLength(0)(返回一维数组str1的长度)
GetValue/SetValue 获取 / 设置指定索引的元素值 str1.GetValue(0)(获取str1[0]);str1.SetValue("郑爽", 1)(设置str1[1]
Contains 判断数组是否包含指定元素(需引入System.Linq str1.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; }; 仅一个参数时,可省略()
单表达式省略{}return Func<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. 选择排序

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

  • 核心代码:

    cs 复制代码
    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 自定义排序规则。

  • 基础用法:

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

    cs 复制代码
    // 升序: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类与数组
cs 复制代码
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 提供的聚合方法,简化计算)。

相关推荐
李昊哲小课9 分钟前
支持向量机SVM
人工智能·算法·机器学习·支持向量机·数据挖掘·sklearn
jndingxin10 分钟前
OpenCV多尺度图像增强算法函数BIMEF()
人工智能·opencv·算法
算法_小学生17 分钟前
Hinge Loss(铰链损失函数)详解:SVM 中的关键损失函数
开发语言·人工智能·python·算法·机器学习·支持向量机
续亮~29 分钟前
基于Spring AI Alibaba的智能知识助手系统:从零到一的RAG实战开发
java·人工智能·spring·springaialibaba
paopaokaka_luck30 分钟前
基于SpringBoot+Vue的汽车租赁系统(协同过滤算法、腾讯地图API、支付宝沙盒支付、WebsSocket实时聊天、ECharts图形化分析)
vue.js·spring boot·后端·websocket·算法·汽车·echarts
giao源35 分钟前
Spring Boot 整合 Shiro 实现单用户与多用户认证授权指南
java·spring boot·后端·安全性测试
kyle~1 小时前
C++---cout、cerr、clog
开发语言·c++·算法
斯内科1 小时前
C#将【程序集引用-依赖关系】展示到NetronLight图表中
c#·流程图·graph
钢铁男儿1 小时前
PyQt5信号与槽(信号与槽的高级玩法)
python·qt·算法
thginWalker2 小时前
拓扑排序/
java·开发语言