Я искал разницу между Select
и , SelectMany
но я не смог найти подходящий ответ. Мне нужно узнать разницу при использовании LINQ To SQL, но я нашел только стандартные примеры массивов.
Может кто-нибудь привести пример LINQ To SQL?
Я искал разницу между 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)}
SelectMany
это . Скорее, это способ, который SelectMany
можно использовать, но на самом деле это не обычный способ его использования.
Where
состояние после SelectMany
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
};
Предыдущий пример взят из блога Дэна 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")
Для отношений 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 для выбранной организации.
Первый «проект» от организации до пользователей, второй напрямую запрашивает таблицу пользователей.
Это более понятно, когда запрос возвращает строку (массив char):
Например, если список «Фрукты» содержит «яблоко»
«Выбрать» возвращает строку:
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 () используется для выравнивания последовательности, в которой каждый из элементов последовательности является отдельным.
У меня 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 }
Просто для альтернативного представления, которое может помочь некоторым функциональным программистам:
Select
является map
SelectMany
есть bind
(или flatMap
для ваших людей Scala / Kotlin)Рассмотрим этот пример:
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 есть два разных массива (первый и второй элемент), ничего не будет удалено.
Еще один пример того, как 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();
usersArray.SelectMany(ua => ua.Phones.Select(p => p.BasePart))
Вот пример кода с инициализированной небольшой коллекцией для тестирования:
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; }
}
В 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" }
Это лучший способ понять, я думаю.
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();
Пример таблицы умножения.