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

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

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

13 ответов


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

живая демонстрация на .NET Fiddle


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

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. Альба
  3. Коста
  4. Вилла
  5. Busquets

...


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

подробнее об этом блоге.


есть несколько перегрузок для 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 
                                   };

предыдущий пример взят из блог Дана IK. Я настоятельно рекомендую вам взглянуть на него.


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

таким образом, вы можете:

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

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


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

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

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

для отношения 1 ко многим,

  1. если начать с "1", SelectMany необходим, он выравнивает многие.
  2. если начать с "Много", 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 для выбранной организации.

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


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

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

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

например, если список "фрукты" содержит "яблоко"

'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 можно использовать для накопления данных объектов sub array.

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

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

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