一起谈.NET技术,C# 中奇妙的函数--联接序列的五种简单方法

  今天我们来看看5种使用Linq函数联接序列的方法,这5种方法可以归入下列两类:

  同类的联接

  Concat()

  Union()

  不同类的联接

  Zip()

  Join()

  GroupJoin()

  Concat() – 串联序列

  最简单的序列合并,concat仅仅是将第二个序列接在第一个序列后面, 注意:返回的序列并没有改变原来元素的顺序:


1. var healthFoods = new List<string> { "fruits", "vegetables", "grains", "proteins" };
2. var myFoods = new List<string> { "grains", "proteins", "M&Ms", "soda" };
3. // 返回序列: fruits, vegetables, grains, proteins, grains, proteins, M&Ms, soda
4. var healthyFirst = healthFoods.Concat(myFoods);
5. // 返回序列: grains, proteins, M&Ms, soda, fruits, vegetables, grains, proteins
6. var mineFirst = myFoods.Concat(healthFoods);

  Union() – 无重复项的串联序列

  该方法用于结合两个没有重复项的集合,也非常适用于任何两个序列。 它将第二个序列结合到第一个序列里,当第二个序列中出现与第一个序列重复的项时,它只保留第一序列的项目。

  是否是重复的项目取决于IEqualityComparer <T> ,如果你没有提供个性化的定义,则使用该类型的默认函数。 请注意,如果 T 是一个自定义的类型,这意味着你同时需要一个有效的Equals() 和 GetHashCode()的定义。


1. // 返回序列: fruits, vegetables, grains, proteins, M&Ms, soda
2. var healthyFirst = healthFoods.Union(myFoods);
3. // 返回序列: grains, proteins, M&Ms, soda, fruits, vegetables
4. var mineFirst = myFoods.Union(healthFoods);

  Zip() – 简单一对一的联接

  该方法针对两个不同类执行一个最简单的联接。 比如给定两个序列,它仅仅将他们的第一个项合并,而后将他们第二个项合并,…,一旦到达较短序列的最后一项,它就会立即停止。

  比方说,比如,我们有下面的类定义:


1. public class Employee
2. {
3. public int Id { get; set; }
4. public string Name { get; set; }
5. public double Salary { get; set; }
6. }
7. public class Seat
8. {
9. public int Id { get; set; }
10. public double Cost { get; set; }
11. }

  然后,我们确定了以下顺序:


1. var employees = new List<Employee>
2. {
3. new Employee { Id = 13, Name = "John Doe", Salary = 13482.50 },
4. new Employee { Id = 42, Name = "Sue Smith", Salary = 98234.13 },
5. new Employee { Id = 99, Name = "Jane Doe", Salary = 32421.12 }
6. };
7. var seats = new List<Seat>
8. {
9. new Seat { Id = 1, Cost = 42 },
10. new Seat { Id = 2, Cost = 42 },
11. new Seat { Id = 3, Cost = 100 },
12. new Seat { Id = 4, Cost = 100 },
13. new Seat { Id = 5, Cost = 125 },
14. new Seat { Id = 6, Cost = 125 },
15. };

  我们可以联接它们,给每个雇员提供一个座位: 


1. var seatingAssignments = employees.Zip(seats, (e, s) => new
2. { EmployeeId = e.Id, SeatId = s.Id });
3. foreach (var seat in seatingAssignments)
4. {
5. Console.WriteLine("雇员: " + seat.EmployeeId + " 预约了座位 " + seat.SeatId);
6.
7. }

  我们可以得到:

  雇员: 13 预约了座位1

  雇员: 42 预约了座位2

  雇员: 99 预约了座位3

  Join() – 满足条件的联接

  “使用 join 子句可以将来自不同源序列并且在对象模型中没有直接关系的元素相关联。 唯一的要求是每个源中的元素需要共享某个可以进行比较以判断是否相等的值。 例如,食品经销商可能具有某种产品的供应商列表以及买主列表。 例如,可以使用 join 子句创建该产品同一指定地区供应商和买主的列表。

  join 子句接受两个源序列作为输入。 每个序列中的元素都必须是可以与另一个序列中的相应属性进行比较的属性,或者包含一个这样的属性。 join 子句使用特殊的 equals 关键字比较指定的键是否相等。 join 子句执行的所有联接都是同等联接。 join 子句的输出形式取决于所执行的联接的具体类型。 ”

  是否相等取决于IEqualityComparer<T>,如果你使用自定义的类型,你需要提供 Equals() 和 GetHashCode() 或者提供一个自定义的 IEqualityComparer<T>. 但是你使用的.NET 中的类型,则一般不需要再另外实现这些函数。

  上例子,使用之前的Employee类,再加一个Badge类,然后我们再创建这一组序列:


1. public class Badge
2. {
3. public int EmployeeId { get; set; }
4. public int BadgeNumber { get; set; }
5. }
6. var employees = new List<Employee>
7. {
8. new Employee { Id = 13, Name = "John Doe", Salary = 13482.50 },
9. new Employee { Id = 42, Name = "Sue Smith", Salary = 98234.13 },
10. new Employee { Id = 99, Name = "Jane Doe", Salary = 32421.12 }
11. };
12. var badges = new List<Badge>
13. {
14. new Badge { EmployeeId = 10, BadgeNumber = 1 },
15. new Badge { EmployeeId = 13, BadgeNumber = 2 },
16. new Badge { EmployeeId = 20, BadgeNumber = 3 },
17. new Badge { EmployeeId = 25, BadgeNumber = 4 },
18. new Badge { EmployeeId = 42, BadgeNumber = 5 },
19. new Badge { EmployeeId = 10, BadgeNumber = 6 },
20. new Badge { EmployeeId = 13, BadgeNumber = 7 },
21. };

  这样我们就可以使用Join 来对它们进行操作了:


1. var badgeAssignments = employees.Join(badges, e => e.Id, b => b.EmployeeId,
2. (e, b) => new { e.Name, b.BadgeNumber });
3. foreach (var badge in badgeAssignments)
4. {
5. Console.WriteLine("Name: " + badge.Name + " has badge " + badge.BadgeNumber);
6. }

  返回的结果是:

  Name: John Doe has badge 2

  Name: John Doe has badge 7

  Name: Sue Smith has badge 5

  Join 对于1:1的关系是非常实用的,或者如果你不在乎返回一些重复的1:N的关系,你也可以是用Join.

  GroupJoin() – 适用于一对多的条件联接

  那么,如果你有1:N的关系,你希望这些结果分类组合在一起就可以用到 GroupJoin(),仍旧用上面的例子:


1. var badgeAssignments = employees.GroupJoin(badges, e => e.Id, b => b.EmployeeId,
2. (e, bList) => new { Name = e.Name, Badges = bList.ToList() });
3. foreach (var assignment in badgeAssignments)
4. {
5. Console.WriteLine(assignment.Name + " has badges:");
6. if (assignment.Badges.Count > 0)
7. {
8. foreach (var badge in assignment.Badges)
9. {
10. Console.WriteLine("\tBadge: " + badge.BadgeNumber);
11. }
12. }
13. else
14. {
15. Console.WriteLine("\tNo badges.");
16. }
17. }

  结果如下:


1. John Doe has badges:
2. Badge: 2
3. Badge: 7
4. Sue Smith has badges:
5. Badge: 5
6. Jane Doe has badges:
7. No badges.

  如果你想进步一强化对Join 和 GroupJoin 区别的了解,可以再一次看看上面两个例子输入的结果。

时间: 2024-08-01 11:17:25

一起谈.NET技术,C# 中奇妙的函数--联接序列的五种简单方法的相关文章

C#“.NET技术” 中奇妙的函数--联接序列的五种简单方法

今天我们来看看5种使用Linq函数联接序列的方法,这5种方法可以归入下列两类: 同类的联接 Concat() Union() 不同类的联接 Zip() Join() GroupJoin() Concat() – 串联序列 最简单的序列合并,concat仅仅是将第二个序列接在第一个序列后面, 注意:返回的序列并没有改变原来元素的顺序: 1. var healthFoods = new List<string> { "fruits", "vegetables"

C# 中奇妙的函数--联接序列的五种简单方法

今天我们来看看5种使用Linq函数联接序列的方法,这5种方法可以归入下列两类: 同类的联接 Concat() Union() 不同类的联接 Zip() Join() GroupJoin() Concat() – 串联序列 最简单的序列合并,concat仅仅是将第二个序列接在第一个序列后面, 注意:返回的序列并没有改变原来元素的顺序: 1. var healthFoods = new List<string> { "fruits", "vegetables"

C# 中奇妙的函数--联接序列的五种“.NET研究”简单方法

今天我们来看看5种使用Linq函数联接序列的方法,这5种方法可以归入下列两类: 同类的联接 Concat() Union() 不同类的联接 Zip() Join() GroupJoin() Concat() – 串联序列 最简单的序列合并,concat仅仅是将第二个序列接在第一个序列后面, 注意:返回的序列并没有改变原来元素的顺序: 1. var healthFoods = new List<string> { "fruits", "vegetables"

一起谈.NET技术,解决T4模板的程序集引用的五种方案

在众多.NET应用下的代码生成方案中,比如CodeDOM,BuildProvider, 我觉得T4是最好的一种.关于T4的基本概念和模板结果,可以参考我的文章<基于T4的代码生成方式>.如果要了解T4具体的应用,则可以参考我的文章<创建代码生成器可以很简单:如何通过T4模板生成代码?>(上篇)(下篇).如果你编写T4模板,你不得不面对一个问题--如何引用一个程序集?VS 2010采用了与VS2008不同的程序集引用的解析机制.本篇文章为你介绍在VS2010下5种不同的程序集引用的方

js中判断对象是否为空的三种实现方法

 本篇文章主要是对js中判断对象是否为空的三种实现方法进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助 在写js脚本的时候经常遇到对象为空或者不是对象的情况,出现这种情况我们可以用if去判断它,然后去执行相应的处理方法,具体判断他们的方法有以下几种:   1.if   (typeOf(x)   ==   "undefined")   2.if   (typeOf(x)   !=   "object")   3.if(!x)   其中第三种是最简单的

一起谈.NET技术,C# 中奇妙的函数之ToLookup

我将和大家一起来学学C#中一些非常有用函数,对于有些人来说可能它们不起眼,因此常常忽略它们.它们不会嚷嚷到:使用我吧!我会让你节省很多的时间,而且让你的代码变得更加的简洁! -- 但是,这些话会从对它们熟悉的程序员的脑海中涌现出来. 好的!先来看看ToLookup: 故事的背景 让我们先来创建一个简单的类来表示产品,产品有ID,类别,和价格,这个类没有什么特别:   public sealed class Product { public int Id { get; set; } public

C“.NET技术”# 中奇妙的函数之ToLookup

我将和大家一起来学学C#中一些非常有用函数,对于有些人来说可能它们不起眼,因此常常忽略它们.它们不会嚷嚷到:使用我吧!我会让你节省很多的时间,而且让你的代码变得更加的简洁! -- 但是,这些话会从对它们熟悉的程序员的脑海中涌现出来. 好的!先来看看ToLookup: 故事的背景 让我们先来创建一个简单的类来表示产品,产品有ID,类别,和价格,这个类没有什么特别:   public sealed class Product { public int Id { get; set; } public

一起谈.NET技术,中软面试题-最新

      中软的面试比较经典,也比较严格,一般有四轮,类似于微软的面试.中软面过以后,根据项目组,会推到美国微软那边运用live meeting & con-call 再面一次.以下是我的面试题及个人的小分析,拿出来和大家share一下.希望更多的人能过这个坎.如有什么问题,可以一起交流.直接进入主题:  1. English communication. (sale yourself, project information, your interesting,and how to deal

一起谈.NET技术,关于C#线程,线程池和并行运算的简单使用和对比

前言:看了书上两个使用C#4.0并行编程的demo,又对照以前收藏的网上几篇讲述线程池的雄文,一并整理,写个示例总结一下.写这篇文章的时候,发现关于线程的好几个基础的重要的知识点自己都不熟悉,而且可能习惯性认知浅薄,所以痛苦的无以复加,不知道到底要说什么.不想看文章的可以直接下载最后的示例,本文代码主要参考Marc Clifton的".NET's ThreadPool Class - Behind The Scenes",对新手也许有帮助. 参考: http://msdn.micros