ChatGPT解决这个技术问题 Extra ChatGPT

Select 和 SelectMany 的区别

我一直在寻找 SelectSelectMany 之间的区别,但找不到合适的答案。我需要了解使用 LINQ To SQL 时的区别,但我发现的只是标准数组示例。

有人可以提供 LINQ To SQL 示例吗?

您可以使用一个函数或两个函数查看 SelectMany 的代码referencesource.microsoft.com/#System.Core/System/Linq/…
如果您熟悉 Kotlin,它对于集合的实现非常相似,例如 map aka C# Select 和 flatMap aka C# SelectMany。基本上,集合的 Kotlin 标准库扩展函数与 C# Linq 库有相似之处。
有人会同意 SelectFromMany 将是一个比 SelectMany 更具描述性的名称吗?

G
Graham

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

Live Demo on .NET Fiddle


Related question 关于嵌套 SelectMany 以展平嵌套的层次结构。
了解更多 resultSelector 下面的链接有助于blogs.interknowlogy.com/2008/10/10/…
另一个带有父级结果的演示:dotnetfiddle.net/flcdCC
U
Uwe Keim

Select many 类似于 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)}

我知道这是旧的,但我想感谢你,它救了我很多! :) 参考这些代码也很有用:stackoverflow.com/questions/3479980/…干杯!
SelectMany 不必像那样使用。它也可以选择仅采用一个功能。
我不知道这样说SelectMany 是否正确。相反,这是一种可以使用 SelectMany 的方式,但实际上并不是正常的使用方式。
这是我理解的最简单的答案。
@ChaimEliyah 这很可能是您最容易理解的答案,但如果这是您阅读的唯一答案,那么我不希望您真正理解 SelectMany() 正在做什么;这根本不代表函数在一般情况下的作用——它只是提供了它能够实现的特定(不寻常)事情。
L
Lews Therin

https://i.stack.imgur.com/XWpx2.png

var players = db.SoccerTeams.Where(c => c.Country == "Spain")
                            .SelectMany(c => c.players);

foreach(var player in players)
{
    Console.WriteLine(player.LastName);
}

德赫亚阿尔巴科斯塔别墅布斯克茨

...


很好的示例数据
您能否为 select 添加一个示例以完成此答案:)
@Harry:来自以前的示例,但有所发展:dotnetfiddle.net/Ku6kLR
老兄忘记了所有的传说......哈维,伊涅斯塔,普约尔:(
S
Sameer Alibhai

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

blog post 中的更多详细信息。


但是第一个返回 Enumerables 类型的 Children 第二个示例返回类型的 parents ?其实我有点糊涂了,你能再开一点吗?
反过来,实际上。第二个将完全扁平化可枚举的层次结构,以便您返回 Children。试试我添加的链接上的文章,看看是否有帮助。
第一个似乎不合法。我认为海报自己弄糊涂了。第二个将返回一个可枚举的父母。
谢谢,实际上是的,这些例子有点令人困惑 :) 但再次感谢您尝试帮助我。
8
8 revs, 4 users 72%

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。我强烈建议你看看它。


S
Selim Yildiz

我了解 SelectMany 的作用类似于加入快捷方式。

这样你就可以:

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

提供的示例有效,但 SelectMany 并不完全像连接一样工作。连接允许“使用”原始表的任何字段以及连接表的任何字段。但是在这里您必须指定附加到原始表的列表的对象。例如,.SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate}); 将不起作用。 SelectMany 相当扁平化列表列表 - 您可以选择任何(但一次只能选择一个)包含的列表作为结果。比较:Inner join in Linq
R
Reza Jenabi

SelectMany() 方法用于展平序列,其中序列的每个元素都是独立的。

我有像这样的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 }

如果一个或多个列表碰巧为空,你还能聚合其他列表吗?由于有几个空结果,我收到一个错误。
A
Alexandr

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


R
Rm558

某些 SelectMany 可能不是必需的。以下 2 个查询给出了相同的结果。

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

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

对于一对多关系,

如果从“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

n
nzrytmn

SelectMany() 的正式描述是:

将序列的每个元素投影到 IEnumerable 并将生成的序列展平为一个序列。

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

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():
    Scruffy
    Sam
    Walker
    Sugar
    Scratches
    Diesel

   Using Select():
   Scruffy
   Sam

   Walker
   Sugar

   Scratches
   Diesel
  */

主要区别在于每个方法的结果,而 SelectMany() 返回一个平坦的结果; Select() 返回一个列表列表,而不是一个扁平的结果集。

因此 SelectMany 的结果是一个类似的列表

{邋遢、山姆、沃克、糖、划痕、柴油}

您可以通过一个 foreach 来迭代每个项目。但是对于 select 的结果,您需要一个额外的 foreach 循环来遍历结果,因为查询返回数组的集合。


R
RickL

无需太技术化-具有许多组织的数据库,每个组织都有许多用户:-

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 列表。

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


M
Matt Klein

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

选择是地图

SelectMany 是绑定的(或者你的 Scala/Kotlin 人员的 flatMap)


E
Eric Bole-Feysot

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

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

'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'

M
Mohammad Galouz Lee

考虑这个例子:

        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 中删除时,因为“SelectMany”会变平并跨多个序列投影。但是 query1 返回字符串数组的序列。并且由于 query1 中有两个不同的数组(第一个和第二个元素),因此不会删除任何内容。


现在最好在末尾包含 .Distinct() 并声明它输出“我”“喜欢”“什么”“我”“喜欢”“我”“喜欢”“什么”“你”“喜欢”
s
snr

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" }

K
KEMBL

另一个示例如何使用 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();

你认为哪个更好?你的或usersArray.SelectMany(ua => ua.Phones.Select(p => p.BasePart))
S
Sharunas Bielskis

这是一个带有用于测试的初始化小集合的代码示例:

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 orders
        List<string> allSKUs = new List<string>();

        //With Select case 2 foreach loops are required
        var 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 required
        allSKUs = 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 operated
        List<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; }
}

u
user5966157

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

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

乘法表示例。


只有当“最佳”的含义发生了巨大变化时。
所以这是你认为最好的方式??那么困难的思维方式是什么?