选择和选择的区别

我一直在寻找SelectSelectMany之间的区别,但我还没有找到合适的答案。我需要学习使用LINQ To时的区别SQL但我找到的都是标准数组示例。

有人能提供一个LINQ toSQL例子吗?

688923 次浏览

我理解SelectMany像连接快捷方式一样工作。

所以你可以:

var orders = customers.Where(c => c.CustomerName == "Acme").SelectMany(c => c.Orders);

SelectMany()允许您以一种需要第二个Select()或循环的方式折叠多维序列。

更多细节在这里博客文章

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 numbersIEnumerable<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 });

Live Demo on. NET Fiddle

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 < 10select new{ LeagueID = helper.league.ID, Team = helper.team};

前面的示例取自Dan的IK博客。我强烈建议您查看一下。

选择是从源元素到结果元素的简单一对一投影。选择-当查询表达式中有多个from子句时,会使用许多:原始序列中的每个元素用于生成新序列。

选择许多类似于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);}
  1. 德赫亚
  2. 阿尔巴
  3. Costa
  4. 别墅
  5. 布斯克茨

某些选择多个可能不是必需的。以下两个查询给出相同的结果。

Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)
Orders.Where(o=>o.Customer.Name=="Tom")

对于一对多关系,

  1. 如果从“1”开始,需要选择多个,它会使多个变平。
  2. 如果从“许多”开始,则不需要选择许多。(仍然可以从“1”中过滤,这也比下面的标准连接查询简单)

from o in Ordersjoin c in Customers on o.CustomerID equals c.IDwhere c.Name == "Tom"select o

我认为这是理解的最好方法。

            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();

乘法表示例。

不需要太技术性-数据库与许多组织,每个组织都有许多用户:-

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();

都返回所选组织的相同 Application ationUser列表。

第一个“项目”从组织到用户,第二个直接查询用户表。

当查询返回字符串(char数组)时更清楚:

例如,如果列表“水果”包含“苹果”

'选择'返回字符串:

Fruits.Select(s=>s)
[0]: "apple"

“选择多个”将字符串展平:

Fruits.SelectMany(s=>s)
[0]: 97  'a'[1]: 112 'p'[2]: 112 'p'[3]: 108 'l'[4]: 101 'e'

只是为了一个可能帮助一些函数式程序员的替代视图:

  • Selectmap
  • SelectManybind(或flatMap为您的Scala/静态编程语言的人)

再举一个例子,说明如何使用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 arraysList<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();

下面是一个代码示例,其中包含用于测试的初始化小集合:

class Program{static void Main(string[] args){List<Order> orders = new List<Order>{new Order{OrderID = "orderID1",OrderLines = new List<OrderLine>{new OrderLine{ProductSKU = "SKU1",Quantity = 1},new OrderLine{ProductSKU = "SKU2",Quantity = 2},new OrderLine{ProductSKU = "SKU3",Quantity = 3}}},new Order{OrderID = "orderID2",OrderLines = new List<OrderLine>{new OrderLine{ProductSKU = "SKU4",Quantity = 4},new OrderLine{ProductSKU = "SKU5",Quantity = 5}}}};
//required result is the list of all SKUs in ordersList<string> allSKUs = new List<string>();
//With Select case 2 foreach loops are requiredvar flattenedOrdersLinesSelectCase = orders.Select(o => o.OrderLines);foreach (var flattenedOrderLine in flattenedOrdersLinesSelectCase){foreach (OrderLine orderLine in flattenedOrderLine){allSKUs.Add(orderLine.ProductSKU);}}
//With SelectMany case only one foreach loop is requiredallSKUs = new List<string>();var flattenedOrdersLinesSelectManyCase = orders.SelectMany(o => o.OrderLines);foreach (var flattenedOrderLine in flattenedOrdersLinesSelectManyCase){allSKUs.Add(flattenedOrderLine.ProductSKU);}
//If the required result is flattened list which has OrderID, ProductSKU and Quantity,//SelectMany with selector is very helpful to get the required result//and allows avoiding own For loops what according to my experience do code faster when// hundreds of thousands of data rows must be operatedList<OrderLineForReport> ordersLinesForReport = (List<OrderLineForReport>)orders.SelectMany(o => o.OrderLines,(o, ol) => new OrderLineForReport{OrderID = o.OrderID,ProductSKU = ol.ProductSKU,Quantity = ol.Quantity}).ToList();}}class Order{public string OrderID { get; set; }public List<OrderLine> OrderLines { get; set; }}class OrderLine{public string ProductSKU { get; set; }public int Quantity { get; set; }}class OrderLineForReport{public string OrderID { get; set; }public string ProductSKU { get; set; }public int Quantity { get; set; }}

考虑这个例子:

        var array = new string[2]{"I like what I like","I like what you like"};//query1 returns two elements sth like this://fisrt element would be array[5]  :[0] = "I" "like" "what" "I" "like"//second element would be array[5] :[1] = "I" "like" "what" "you" "like"IEnumerable<string[]> query1 = array.Select(s => s.Split(' ')).Distinct();
//query2 return back flat result sth like this :// "I" "like" "what" "you"IEnumerable<string> query2 = array.SelectMany(s => s.Split(' ')).Distinct();

因此,正如您所看到的那样,像“I”或“like”这样的重复值已从query2中删除,因为“选择多个”展平并跨多个序列投影。但是query1返回字符串数组的序列。并且由于query1中有两个不同的数组(第一个和第二个元素),因此不会删除任何内容。

SelectMany方法将IEnumerable<IEnumerable<T>>打倒为IEnumerable<T>,就像共产主义一样,每个元素的行为方式都是相同的(一个愚蠢的人拥有与一个天才相同的权利)。

var words = new [] { "a,b,c", "d,e", "f" };var splitAndCombine = words.SelectMany(x => x.Split(','));// returns { "a", "b", "c", "d", "e", "f" }

多选方法用于压平序列,其中序列的每个元素都是单独的。

我有类user像这样

class User{public string UserName { get; set; }public List<string> Roles { get; set; }}

主要:

var users = new List<User>{new User { UserName = "Reza" , Roles = new List<string>{"Superadmin" } },new User { UserName = "Amin" , Roles = new List<string>{"Guest","Reseption" } },new User { UserName = "Nima" , Roles = new List<string>{"Nurse","Guest" } },};
var query = users.SelectMany(user => user.Roles, (user, role) => new { user.UserName, role });
foreach (var obj in query){Console.WriteLine(obj);}//output
//{ UserName = Reza, role = Superadmin }//{ UserName = Amin, role = Guest }//{ UserName = Amin, role = Reseption }//{ UserName = Nima, role = Nurse }//{ UserName = Nima, role = Guest }

您可以对任何序列项使用操作

int[][] numbers = {new[] {1, 2, 3},new[] {4},new[] {5, 6 , 6 , 2 , 7, 8},new[] {12, 14}};
IEnumerable<int> result = numbers.SelectMany(array => array.Distinct()).OrderBy(x => x);
//output
//{ 1, 2 , 2 , 3, 4, 5, 6, 7, 8, 12, 14 }
 List<List<int>> numbers = new List<List<int>> {new List<int> {1, 2, 3},new List<int> {12},new List<int> {5, 6, 5, 7},new List<int> {10, 10, 10, 12}};
IEnumerable<int> result = numbers.SelectMany(list => list).Distinct().OrderBy(x=>x);
//output
// { 1, 2, 3, 5, 6, 7, 10, 12 }

选择许多()的正式描述是:

将序列的每个元素投影到一个IENumable并展平将结果序列合并为一个序列。

选择多个()将结果序列展平为一个序列,并对其中的每个元素调用结果选择器函数。

class PetOwner{public string Name { get; set; }public List<String> Pets { get; set; }}
public static void SelectManyEx(){PetOwner[] petOwners ={ new PetOwner { Name="Higa, Sidney",Pets = new List<string>{ "Scruffy", "Sam" } },new PetOwner { Name="Ashkenazi, Ronen",Pets = new List<string>{ "Walker", "Sugar" } },new PetOwner { Name="Price, Vernette",Pets = new List<string>{ "Scratches", "Diesel" } } };
// Query using SelectMany().IEnumerable<string> query1 = petOwners.SelectMany(petOwner => petOwner.Pets);
Console.WriteLine("Using SelectMany():");
// Only one foreach loop is required to iterate// through the results since it is a// one-dimensional collection.foreach (string pet in query1){Console.WriteLine(pet);}
// This code shows how to use Select()// instead of SelectMany().IEnumerable<List<String>> query2 =petOwners.Select(petOwner => petOwner.Pets);
Console.WriteLine("\nUsing Select():");
// Notice that two foreach loops are required to// iterate through the results// because the query returns a collection of arrays.foreach (List<String> petList in query2){foreach (string pet in petList){Console.WriteLine(pet);}Console.WriteLine();}}
/*This code produces the following output:
Using SelectMany():ScruffySamWalkerSugarScratchesDiesel
Using Select():ScruffySam
WalkerSugar
ScratchesDiesel*/

主要区别在于每个方法的结果,而Select许多()返回一个平面结果;选择()返回列表列表而不是平面结果集。

因此选择多个的结果是一个列表,如

{Scruffy,Sam,Walker,糖,划痕,柴油}

您可以仅通过一个Foreach对每个项目进行迭代。但是对于选择的结果,您需要一个额外的Foreach循环来迭代结果,因为查询返回数组的集合。