分享好友 编程语言首页 频道列表

重学c#系列——linq(3) [二十九]

C/C++教程  2023-02-09 10:110

前言

继续介绍一些复杂的linq。

正文

groupjoin 这个函数:

有department

public class Deployment
{
	public string Id { get; set; }

	public Deployment(string id)
	{
		Id = id;
	}
}

有Employee:

public class Employee
{
	public string DepartmentId { get; set; }

	public string Name { get; set; }

	public Employee(string name, string deploymentId)
	{
		Name = name;
		DepartmentId = deploymentId;
	}
}

现在要实现Deployment和Employee,一对多的关系:

List<Deployment> a = new List<Deployment>()
{
	new Deployment("1"),
	new Deployment("2"),
};

List<Employee> e = new List<Employee>()
{
	new Employee("张三","1"),
	new Employee("李四","1"),
	new Employee("王五","2"),
};

如果我们使用join的话,那么就是:

Deployment("1") Employee("张三","1")
Deployment("1") Employee("李四","1")
Deployment("2") Employee("王五","2")

就是这种平铺的关系。然后再使用group by。

Deployment("1")
   Employee("张三","1")
   Employee("李四","1")
Deployment("2")
   Employee("王五","2")

现在有一个函数可以直接到达这种效果,那么就是groupjoin:

static void Main(string[] args)
{
	List<Deployment> a = new List<Deployment>()
	{
		new Deployment("1"),
		new Deployment("2"),
	};

	List<Employee> e = new List<Employee>()
	{
		new Employee("张三","1"),
		new Employee("李四","1"),
		new Employee("王五","2"),
	};

	var  c = a.GroupJoin(e, deployment => deployment.Id,
		employee => employee.DepartmentId,
		(department, exployees) =>(department.Id, exployees)
	   );
	
	Console.ReadKey();
}

其实可以看到这个exployees,最终运行时是一个Igroup类型,这和join还有group by不同之处。

然后这里写一下join和group by的。

static void Main(string[] args)
{
    List<Deployment> a = new List<Deployment>()
    {
        new Deployment("1"),
        new Deployment("2"),
        new Deployment("3")
    };

    List<Employee> e = new List<Employee>()
    {
        new Employee("张三","1"),
        new Employee("李四","1"),
        new Employee("王五","2"),
    };

    var f = from a1 in a
        join e1 in e on a1.Id equals e1.DepartmentId into temps
        from tt in temps.DefaultIfEmpty()
        select (a1.Id, (a1.Id, tt));
    var d = from f1 in f
        group f1 by f1.Id; 

    Console.ReadKey();
}

这里要说明的就是groupjoin 是一个左连接。

上面用的是linq的查询表达式,因为join 方法其实是inner join。

对于表达式来说其实最终还是生成方法而已,IL 来说没有表达式这回事,可以理解为c#的语法糖。

看下如果上述的linq用方法来怎么写吧。

其实还是用的是groupjoin:

这里可以看出,其实上述这个linq表达式就是groupjoin 然后用selectmany拆开,然后在用group再聚合。。

如果你只需要获取每个部门下的员工,用groupjoin 效率是更高的。

当然这里主要是说明linq 的表达式最终都是方法,语法糖而已。表达式是为了让我们更加清晰的去描述。

如果写一些复杂的linq,那么最好去用linq表达式。通过如果是groupjoin 就能实现的,就没必要去使用,这可能效率更低。

这里提到了selectmany,那么就讲述一下selectmany。 group by 是聚合,那么selectmany就是拆分。

public class BasketballTeam
{
	public string Name { get; set; }

	public string[] TeamMember;
}

static void Main(string[] args)
{
	List<BasketballTeam> list = new List<BasketballTeam>();
	BasketballTeam basketballTeam = new BasketballTeam();
	basketballTeam.Name = "无敌球队";
	basketballTeam.TeamMember = new string[] { "张三", "李四", "王五" };
	BasketballTeam basketballTeam1 = new BasketballTeam();
	basketballTeam1.Name = "小新球团";
	basketballTeam1.TeamMember = new string[] { "张嘛子", "李老帽", "王七三" };
	list.Add(basketballTeam);
	list.Add(basketballTeam1);
	var a = list.SelectMany(u=> u.TeamMember, (u,s)=> u.Name + " " + s);

	foreach (var item in a)
	{
		Console.WriteLine(item);
	}
	Console.ReadKey();
}

selectMany 就是用来处理集合的集合的,是一个展开过程。

上面代码是遍历一组球队的全部成员。

有兴趣可以去看下代码,其实都能猜到,就是两个foreach 循环的封装。

下面介绍一下c# 匿名类型对linq使用:

如果临时使用,那么可以使用匿名类型。

匿名类型其实不是说真的匿名,其实是编译的时候会生成一个类。

如果两者完全一样,那么将会生成一个类,如果只要有一点结构不同,那么会生成两个类。

因为上面一致,所以赋值。

顺序不一致,依然生成不同的类。

不过现在元组替代了匿名类型,因为元组在方法外部也可以使用。

然后值得注意的是匿名类型是引用类型,而元组是值类型,如果经常拷贝且内存超过128位就用匿名,否则就是元组。

其实不用纠结元组和匿名,就是元组的功能比匿名强,但是因为元组是值类型,如果经常赋值拷贝的话那么肯定是引用类型更好,所以匿名类型这时候才是用武之地。

下一节查询表达式,也是linq的终章。后面一张就是异步(并行和并发),这个考虑在汇编系列之后,因为介绍task实现原理,需要用到il,用到il就需要一些汇编知识。

查看更多关于【C/C++教程】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
C++ LeetCode1832题解判断句子是否为全字母句
目录LeetCode 1832.判断句子是否为全字母句方法一:统计AC代码C++LeetCode 1832.判断句子是否为全字母句力扣题目链接:leetcode.cn/problems/ch…全字母句 指包含英语字母表中每个字母至少一次的句子。给你一个仅由小写英文字母组成的字符串 sentence ,请

0评论2023-02-09795

C++使用宏实现动态库加载 c++加载静态库
目录前言一、为什么使用宏1、Windows加载2、Linux加载3、宏加载二、具体实现三、如何使用1、引用头文件2、添加导入宏3、直接调用总结前言开发的时候,有些项目不能静态链接动态库,需要程序运行时加载动态库,这个时候根据不同平台我们通常使用LoadLibrary或d

0评论2023-02-09577

C++ LeetCode1805字符串不同整数数目
目录LeetCode 1805.字符串中不同整数的数目方法一:遍历拆分AC代码C++LeetCode 1805.字符串中不同整数的数目力扣题目链接:leetcode.cn/problems/nu…给你一个字符串 word ,该字符串由数字和小写英文字母组成。请你用空格替换每个不是数字的字符。例如,"a12

0评论2023-02-09928

C++11中的stoi & stod用法
目录C++11的stoistodc++11新特性集合总结C++11的stoistod#include iostream #include stringusing namespace std;int main(){string str="123";int a=stoi(str);//如果遇到非法输入,stoi会自动截取最前面的数字,知道遇到不是数字为止//所以说如果是浮点数,

0评论2023-02-09804

C++ LeetCode1769移动所有球到每个盒子所需最小操作数示例
目录LeetCode 1769.移动所有球到每个盒子所需的最小操作数方法一:数学思维AC代码C++LeetCode 1769.移动所有球到每个盒子所需的最小操作数力扣题目链接:leetcode.cn/problems/mi…有 n 个盒子。给你一个长度为 n 的二进制字符串 boxes ,其中 boxes[i] 的

0评论2023-02-09430

C++ Boost shared_ptr共享指针详细讲解
目录一、提要二、智能指针boost::shared_ptr与boost::scoped_ptr三、智能指针 boost::shared_ptr用法示例1示例2示例3示例4示例5一、提要boost::shared_ptr是另一个智能指针,与 boost::scoped_ptr有很大不同,本文阐述这种区别。二、智能指针boost::shared_pt

0评论2023-02-09927

C++ Boost Thread线程使用示例详解
目录一、并行编程二、生成何管理Threads练习一、并行编程以下库支持并行编程模型。Boost.Thread 允许您创建和管理自己的线程。Boost.Atomic 允许您通过多个线程的原子操作访问整数类型的变量。Boost.Lockfree 提供线程安全的容器。Boost.MPI 起源于超级计算机

0评论2023-02-09837

更多推荐