Разница между Select и SelectMany

Я искал разницу между Select и SelectMany, но я не смог найти подходящий ответ. Мне нужно узнать разницу при использовании LINQ To SQL, но все, что я нашел, это стандартные примеры массивов.

Может ли кто-нибудь предоставить пример LINQ To SQL?

Ответы

Ответ 1

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

Ответ 2

Выбрать несколько - это как операция перекрестного объединения в 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)}

Ответ 3

enter image description here

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

foreach(var player in players)
{
    Console.WriteLine(player.LastName);
}
  1. Де Хеа
  2. Alba
  3. Costa
  4. Villa
  5. Бускетс

...

Ответ 4

SelectMany() позволяет свернуть многомерную последовательность таким образом, чтобы в противном случае потребовался бы второй Select() или цикл.

Подробнее об этом сообщении в блоге.

Ответ 5

Есть несколько перегрузок в 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 IK. Я настоятельно рекомендую вам взглянуть на него.

Ответ 6

Я понимаю SelectMany, чтобы работать как ярлык соединения.

Итак, вы можете:

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

Ответ 7

Выбор - это простая взаимно-однозначная проекция от исходного элемента к элементу результата. Выбрать- Многие используются, когда в выражении запроса есть несколько из предложений: каждый элемент в исходной последовательности используется для генерации новой последовательности.

Ответ 8

Некоторые функции SelectMany могут не понадобиться. Ниже 2 запроса дают тот же результат.

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

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

Для отношений "один-ко-многим"

  • Если "Начать" с "1", требуется SelectMany, он сглаживает многие.
  • Если "Начать" с "Много", SelectMany не требуется. ( все еще можно фильтровать от "1" , это проще, чем ниже стандартного запроса на соединение)

from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o

Ответ 9

Без получения технической базы данных со многими организациями, каждая со многими пользователями: -

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 для выбранной организации.

Первые "проекты" от "Организации к пользователям", вторая запрашивает таблицу "Пользователи" напрямую.

Ответ 10

Это более ясно, когда запрос возвращает строку (массив символов):

Например, если в списке "Фрукты" содержится "яблоко",

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

Ответ 11

Просто для альтернативного представления, которое может помочь некоторым функциональным программистам:

  • Select map
  • SelectMany bind (или flatMap для ваших людей Scala/Kotlin)

Ответ 12

Еще один пример того, как можно использовать SelectMany + Select для накопления данных объектов подмассива.

Предположим, у нас есть пользователи с их телефонами:

class Phone { 
    public string BasePart = "555-xxx-xxx"; 
}

class User { 
    public string Name = "Xxxxx";
    public List<Phone> Phones; 
}

Теперь нам нужно выбрать базовые части всех телефонов для всех пользователей:

var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();

Ответ 13

Вот пример кода с инициализированной небольшой коллекцией для тестирования:

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

Ответ 14

Это лучший способ понять, что я думаю.

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

Пример таблицы умножения.