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

解惑LINQ中的SelectMany用法

在 C# 中,SelectMany 是 LINQ(语言集成查询) 中的一个强大方法,用于将嵌套的集合 “扁平化”(Flatten),并对每个元素应用转换函数。它在处理多维数据结构时特别有用,例如从集合的集合中提取单个元素序列。

1. 基本概念

  • 作用:将一个包含多个集合的集合展开为一个单级集合,并可对每个元素应用转换。
  • 适用场景:处理嵌套数据结构(如列表的列表、数组的数组),或需要跨集合查询元素。

2. 核心重载方法

(1)无转换函数的重载
IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source,Func<TSource, IEnumerable<TResult>> selector
);
  • 参数
    • source:源集合(如 List<List<int>>)。
    • selector:将每个源元素映射为一个子集合的函数。
  • 返回值:所有子集合合并后的单级序列。
(2)带索引的重载
IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source,Func<TSource, int, IEnumerable<TResult>> selector
);
  • 特点selector 函数的第二个参数为元素索引,可用于更复杂的转换。
(3)带结果选择器的重载
IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source,Func<TSource, IEnumerable<TCollection>> collectionSelector,Func<TSource, TCollection, TResult> resultSelector
);
  • 特点:通过 resultSelector 组合源元素和子集合元素,生成最终结果。

3. 示例:无转换函数的扁平化

假设我们有一个包含多个列表的列表,需要将其展开为一个单级列表:

List<List<int>> nestedList = new List<List<int>>
{new List<int> { 1, 2 },new List<int> { 3, 4, 5 },new List<int> { 6 }
};// 使用 SelectMany 扁平化
IEnumerable<int> flattened = nestedList.SelectMany(x => x);// 输出:1, 2, 3, 4, 5, 6
foreach (int num in flattened)
{Console.Write(num + ", ");
}

4. 示例:带转换函数的 SelectMany

假设有一个 Person 类,每个 Person 有多个 Address,需要提取所有地址的城市:

class Person
{public string Name { get; set; }public List<Address> Addresses { get; set; }
}class Address
{public string City { get; set; }
}// 创建数据
List<Person> people = new List<Person>
{new Person{Name = "Alice",Addresses = new List<Address>{new Address { City = "New York" },new Address { City = "London" }}},new Person{Name = "Bob",Addresses = new List<Address>{new Address { City = "Paris" }}}
};// 提取所有城市(扁平化并转换)
IEnumerable<string> cities = people.SelectMany(p => p.Addresses.Select(a => a.City));// 输出:New York, London, Paris
foreach (string city in cities)
{Console.Write(city + ", ");
}

5. 示例:带索引的 SelectMany

使用元素索引生成更复杂的结果:

string[] sentences = { "Hello world", "Goodbye moon" };// 每个单词前加上其所在句子的索引
var result = sentences.SelectMany((sentence, index) =>sentence.Split(' ').Select(word => $"[{index}]: {word}")
);// 输出:[0]: Hello, [0]: world, [1]: Goodbye, [1]: moon
foreach (var item in result)
{Console.Write(item + ", ");
}

6. 示例:带结果选择器的 SelectMany

组合源元素和子集合元素:

List<string> words = new List<string> { "ABC", "DEF" };// 结果选择器:将每个字符与原单词组合
var result = words.SelectMany(word => word,  // 子集合选择器:将单词拆分为字符(word, character) => $"({word}, {character})"  // 结果选择器
);// 输出:(ABC, A), (ABC, B), (ABC, C), (DEF, D), (DEF, E), (DEF, F)
foreach (var item in result)
{Console.Write(item + ", ");
}

7. SelectMany vs Select

方法作用结果类型
Select对每个元素应用转换函数,返回与源集合数量相同的新集合。IEnumerable<TResult>
SelectMany将嵌套集合展开并应用转换,返回合并后的单级集合(数量可能多于源集合)。IEnumerable<TResult>(扁平化)

8. 应用场景

  1. 数据库查询
    在 EF Core 中查询嵌套导航属性(如 Orders.SelectMany(o => o.Items))。

  2. 文本处理
    将多行文本拆分为单词集合。

  3. 事件处理
    将多个事件源的事件合并为一个流。

  4. 并行计算
    将任务集合展开为单个任务序列执行。

9. 性能注意事项

  • SelectMany 是延迟执行的,直到迭代时才会真正展开集合。
  • 对于深层嵌套的集合(如三维数组),多次调用 SelectMany 可能影响性能,可考虑分阶段处理。

总结

SelectMany 是处理嵌套数据结构的核心工具,它通过 “扁平化 + 转换” 的组合,让开发者可以简洁地操作复杂数据。理解其重载方法的差异(尤其是带结果选择器的版本),能帮助你更灵活地处理各种数据场景。

http://www.dtcms.com/a/287853.html

相关文章:

  • 48Days-Day03 | 删除公共字符,两个链表的第一个公共结点,mari和shiny
  • CCF编程能力等级认证GESP—C++8级—20250628
  • 【EMC设计基础--信号环路分析、PCB设计规则】
  • 深入解析文件操作(上)- 二进制文件和文本文件,流的概念,文件的打开和关闭
  • Visual Studio Code(VSCode)中设置中文界面
  • 使用C#对象将WinRiver项目文件进行复杂的XML序列化和反序列化实例详解
  • STM32_Hal库学习ADC
  • XSS的反射型、DOM型、存储型漏洞
  • sqli-labs靶场通关笔记:第32-33关 宽字节注入
  • Go语言中的类型转换与类型推断解析
  • Spring AI硬核攻略:235个模块解析 + 6大场景实战
  • view和pure的区别
  • 智能合约代理与批量调用优化:最小代理与MultiCall的应用
  • Python趣味算法:百钱百鸡问题——双重循环优化与算法效率分析
  • 【Bluedroid】btif_av_sink_execute_service之服务器启用源码流程解析
  • Typecho博客Ajax评论功能实现全攻略
  • 我是怎么设计一个防重复提交机制的(库存出库场景)
  • 【C语言进阶】结构体
  • Windows原生环境配置Claude Code MCP(通过JSON)
  • 简单易懂,快表 详解
  • 有趣的算法题:有时针分针秒针的钟表上,一天之内,时针和分针可重合多少次?分别在什么时刻重合?
  • 【Python】Pandas
  • rustdesk客户端编译
  • QT窗口(7)-QColorDiag
  • 根据ARM手册,分析ARM架构中,原子操作的软硬件实现的底层原理
  • tailscale在ubuntu22.04上使用
  • Unity物理响应函数与触发器
  • LVS详解
  • GitHub 趋势日报 (2025年07月18日)
  • 【图像处理基石】什么是小波变换?