Select和SelectMany之间的区别
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Select和SelectMany之间的区别相关的知识,希望对你有一定的参考价值。
我一直在寻找Select
和SelectMany
之间的区别,但我找不到合适的答案。我需要了解使用LINQ To SQL时的不同之处,但我发现的只是标准数组示例。
有人可以提供LINQ To SQL示例吗?
SelectMany
展平返回列表列表的查询。例如
public class PhoneNumber
{
public string Number { get; set; }
}
public class Person
{
public IEnumerable<PhoneNumber> PhoneNumbers { get; set; }
public string Name { get; set; }
}
IEnumerable<Person> people = new List<Person>();
// Select gets a list of lists of phone numbers
IEnumerable<IEnumerable<PhoneNumber>> phoneLists = people.Select(p => p.PhoneNumbers);
// SelectMany flattens it to just a list of phone numbers.
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers);
// And to include data from the parent in the result:
// pass an expression to the second parameter (resultSelector) in the overload:
var directory = people
.SelectMany(p => p.PhoneNumbers,
(parent, child) => new { parent.Name, child.Number });
只是为了一个可以帮助一些功能程序员的替代视图:
Select
是map
SelectMany
是bind
(或者你的Scala / Kotlin人的flatMap
)
当查询返回一个字符串(一个char数组)时,它会更清楚:
例如,如果列表'Fruits'包含'apple'
'Select'返回字符串:
Fruits.Select(s=>s)
[0]: "apple"
'SelectMany'展平字符串:
Fruits.SelectMany(s=>s)
[0]: 97 'a'
[1]: 112 'p'
[2]: 112 'p'
[3]: 108 'l'
[4]: 101 'e'
还有一个例子可以使用SelectMany + Select来累积子数组对象数据。
假设我们有用户手机:
class Phone {
public string BasePart = "555-xxx-xxx";
}
class User {
public string Name = "Xxxxx";
public List<Phone> Phones;
}
现在我们需要选择所有用户的所有手机的BaseParts:
var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();
这是了解我认为最好的方式。
var query =
Enumerable
.Range(1, 10)
.SelectMany(ints => Enumerable.Range(1, 10), (a, b) => $"{a} * {b} = {a * b}")
.ToArray();
Console.WriteLine(string.Join(Environment.NewLine, query));
Console.Read();
乘法表示例。
选择很多像cross join operation in SQL,它需要交叉产品。 例如,如果我们有
Set A={a,b,c}
Set B={x,y}
选择多个可用于获取以下设置
{ (x,a) , (x,b) , (x,c) , (y,a) , (y,b) , (y,c) }
请注意,这里我们采用可以从集合A和集合B的元素中进行的所有可能组合。
这是您可以尝试的LINQ示例
List<string> animals = new List<string>() { "cat", "dog", "donkey" };
List<int> number = new List<int>() { 10, 20 };
var mix = number.SelectMany(num => animals, (n, a) => new { n, a });
混合物将具有扁平结构的以下元素
{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}
var players = db.SoccerTeams.Where(c => c.Country == "Spain")
.SelectMany(c => c.players);
foreach(var player in players)
{
Console.WriteLine(player.LastName);
}
- 德吉亚
- 阿尔巴
- 哥斯达黎加
- 别墅
- 布斯克茨
...
SelectMany()
允许您以一种原本需要第二个Select()
或循环的方式折叠多维序列。
更多细节在这个blog post。
SelectMany
有几个重载。其中一个允许您在遍历层次结构时跟踪父级和子级之间的任何关系。
示例:假设您具有以下结构:League -> Teams -> Player
。
您可以轻松返回平坦的球员集合。但是,您可能会失去对玩家所属团队的任何引用。
幸运的是,出于此目的存在过载:
var teamsAndTheirLeagues =
from helper in leagues.SelectMany
( l => l.Teams
, ( league, team ) => new { league, team } )
where helper.team.Players.Count > 2
&& helper.league.Teams.Count < 10
select new
{ LeagueID = helper.league.ID
, Team = helper.team
};
前面的例子来自Dan's IK blog。我强烈建议你看一下。
我理解SelectMany像连接快捷方式一样工作。
所以你可以:
var orders = customers
.Where(c => c.CustomerName == "Acme")
.SelectMany(c => c.Orders);
选择是从源元素到结果元素的简单一对一投影。当查询表达式中有多个from子句时,使用Select- Many:原始序列中的每个元素用于生成新序列。
某些SelectMany可能没有必要。低于2的查询给出相同的结果。
Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)
Orders.Where(o=>o.Customer.Name=="Tom")
对于1对多的关系,
- 如果从“1”开始,需要SelectMany,它会使许多人变平。
- 如果从“Many”开始,则不需要SelectMany。 (仍然可以从“1”过滤,这也比下面的标准连接查询简单)
from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o
没有太过技术化 - 有许多组织的数据库,每个组织都有很多用户: -
var orgId = "123456789";
var userList1 = db.Organizations
.Where(a => a.OrganizationId == orgId)
.SelectMany(a => a.Users)
.ToList();
var userList2 = db.Users
.Where(a => a.OrganizationId == orgId)
.ToList();
两者都返回所选组织的相同ApplicationUser列表。
第一个“项目”从组织到用户,第二个直接查询Users表。
以上是关于Select和SelectMany之间的区别的主要内容,如果未能解决你的问题,请参考以下文章
获取所有上级的所有下级节点且Select和SelectMany的用法作用和区别