Я искал разницу между 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 });
Выбирать многие - это как операция перекрестного соединения в 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()
или цикл.
Подробнее об этом сообщении в блоге.
Есть несколько перегрузок в 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. Я настоятельно рекомендую вам взглянуть на него.
Я понимаю SelectMany, чтобы работать как ярлык соединения.
Итак, вы можете:
var orders = customers
.Where(c => c.CustomerName == "Acme")
.SelectMany(c => c.Orders);
.SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate});
не будет работать. SelectMany довольно сглаживает список списков - и вы можете выбрать любой (но только по одному) из содержащихся списков для результата. Для сравнения: внутреннее соединение в Linq .
Выбор - это простая взаимно-однозначная проекция от исходного элемента к элементу результата. Выбрать- Многие используются, когда в выражении запроса есть несколько из предложений: каждый элемент в исходной последовательности используется для генерации новой последовательности.
Некоторые функции SelectMany могут не понадобиться. Ниже 2 запроса дают тот же результат.
Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)
Orders.Where(o=>o.Customer.Name=="Tom")
Для отношений "один-ко-многим"
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
map
SelectMany
bind
(или flatMap
для ваших людей Scala/Kotlin)Это более ясно, когда запрос возвращает строку (массив символов):
Например, если в списке "Фрукты" содержится "яблоко",
'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'
Это лучший способ понять, что я думаю.
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();
Пример таблицы умножения.