前言
繼續介紹一些複雜的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就需要一些彙編知識。