Linq中的设置操作 (C#):Distinct 和 DistinctBy、Except 和 ExceptBy、Intersect 和 IntersectBy、Union 和 UnionBy
LINQ 中的集运算是指根据相同或单独集合中是否存在等效元素来生成结果集的查询运算。
注:这些示例使用 System.Collections.Generic.IEnumerable<T> 数据源。 基于 System.Linq.IQueryProvider 的数据源使用 System.Linq.IQueryable<T> 数据源和表达式树。 表达式树对允许的 C# 语法有限制。 此外,每个 IQueryProvider 数据源(如 EF Core)可能会施加更多限制。
1、Distinct 和 DistinctBy
以下示例演示字符串序列上 Enumerable.Distinct 方法的行为。 返回的序列包含输入序列的唯一元素。
string[] words = ["the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"]; IEnumerable<string> query = from word in words.Distinct() select word; foreach (var str in query) { Console.WriteLine(str); } /* This code produces the following output: * * the * quick * brown * fox * jumped * over * lazy * dog */
DistinctBy 是 Distinct
的替代方法,它采用 keySelector
。 keySelector
用作源类型的比较鉴别器。 在以下代码中,单词根据其 Length
进行区分,并且显示每个长度的第一个单词:
string[] words = ["the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"]; foreach (string word in words.DistinctBy(p => p.Length)) { Console.WriteLine(word); } // This code produces the following output: // the // quick // jumped // over
2、Except 和 ExceptBy
1)Except
以下示例演示 Enumerable.Except 的行为。 返回的序列只包含位于第一个输入序列但不位于第二个输入序列的元素。
string[] words1 = ["the", "quick", "brown", "fox"]; string[] words2 = ["jumped", "over", "the", "lazy", "dog"]; IEnumerable<string> query = from word in words1.Except(words2) select word; foreach (var str in query) { Console.WriteLine(str); } /* This code produces the following output: * * quick * brown * fox */
2)ExceptBy
方法是 Except 的替代方法,它采用可能是异构类型的两个序列和一个 keySelector。 keySelector 的类型与第一个集合的类型相同。 请考虑以下要排除的 Teacher 数组和教师 ID。 若要查找第一个集合中没有出现在第二个集合中的教师,可以将教师的 ID 投影到第二个集合中:
本文中的以下示例使用此区域的常见数据源。
每个 Student 都有年级、主要院系和一系列分数。 Teacher 还有一个 City 属性,用于标识教师的授课校区。 Department 有一个名称,以及对担任院系主任的 Teacher 的引用。
public enum GradeLevel { FirstYear = 1, SecondYear, ThirdYear, FourthYear }; public class Student { public required string FirstName { get; init; } public required string LastName { get; init; } public required int ID { get; init; } public required GradeLevel Year { get; init; } public required List<int> Scores { get; init; } public required int DepartmentID { get; init; } } public class Teacher { public required string First { get; init; } public required string Last { get; init; } public required int ID { get; init; } public required string City { get; init; } } public class Department { public required string Name { get; init; } public int ID { get; init; } public required int TeacherID { get; init; } }
int[] teachersToExclude = [ 901, // English 965, // Mathematics 932, // Engineering 945, // Economics 987, // Physics 901 // Chemistry ]; foreach (Teacher teacher in teachers.ExceptBy( teachersToExclude, teacher => teacher.ID)) { Console.WriteLine($"{teacher.First} {teacher.Last}"); }
在以上 C# 代码中:
已筛选 teachers 数组以仅包含不在 teachersToExclude 数组中的那些教师。
teachersToExclude 数组包含所有部门负责人的 ID 值。
对 ExceptBy 的调用会生成一个新的值集,这些值被写入到控制台。
新的值集的类型为 Teacher,这是第一个集合的类型。 对于 teachers 数组中的每个 teacher,如果在 teachersToExclude 数组中没有相应 ID 值,则会写入到控制台。
3、Intersect 和 IntersectBy
1)Intersect
以下示例演示 Enumerable.Intersect 的行为。 返回的序列包含两个输入序列共有的元素。
string[] words1 = ["the", "quick", "brown", "fox"]; string[] words2 = ["jumped", "over", "the", "lazy", "dog"]; IEnumerable<string> query = from word in words1.Intersect(words2) select word; foreach (var str in query) { Console.WriteLine(str); } /* This code produces the following output: * * the */
2)IntersectBy
IntersectBy 方法是 Intersect 的替代方法,它采用可能是异构类型的两个序列和一个 keySelector。 keySelector 用作第二个集合类型的比较鉴别器。 请考虑以下学生和教师数组。 查询按名称匹配每个序列中的项,以查找那些也是教师的学生:
foreach (Student person in students.IntersectBy( teachers.Select(t => (t.First, t.Last)), s => (s.FirstName, s.LastName))) { Console.WriteLine($"{person.FirstName} {person.LastName}"); }
在上述 C# 代码中:
该查询通过比较名称生成 Teacher 和 Student 的交集。
只有在这两个阵列中都找到的人员才会出现在结果序列中。
将生成的 Student 实例写入控制台。
4、Union 和 UnionBy
1)Union
以下示例演示对两个字符串序列执行的联合操作。 返回的序列包含两个输入序列的唯一元素。
string[] words1 = ["the", "quick", "brown", "fox"]; string[] words2 = ["jumped", "over", "the", "lazy", "dog"]; IEnumerable<string> query = from word in words1.Union(words2) select word; foreach (var str in query) { Console.WriteLine(str); } /* This code produces the following output: * * the * quick * brown * fox * jumped * over * lazy * dog */
2)UnionBy
UnionBy 方法是 Union
的替代方法,它采用相同类型的两个序列和一个 keySelector
。 keySelector
用作源类型的比较鉴别器。 以下查询生成所有人员(学生或教师)的列表。 同时也是教师的学生只会被添加到并集中一次:
foreach (var person in students.Select(s => (s.FirstName, s.LastName)).UnionBy( teachers.Select(t => (FirstName: t.First, LastName: t.Last)), s => (s.FirstName, s.LastName))) { Console.WriteLine($"{person.FirstName} {person.LastName}"); }
在上述 C# 代码中:
teachers
和students
数组使用其名称作为键选择器编织在一起。- 生成的名称将写入控制台。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
2021-01-09 web storage的用法
2019-01-09 使用C#WebClient类访问(上传/下载/删除/列出文件目录)
2017-01-09 ADO.NET对象模型
2017-01-09 趣味理解ADO.NET对象模型
2017-01-09 C# ToString格式大全
2017-01-09 C#中A a=new B()的意义
2017-01-09 sql中时间的一些特殊转换