私は違いを検索してきた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後の状態も示すとよいでしょう
SelectMany()
2 Select()
次元ループを必要とする方法で多次元シーケンスを折りたたむことができます。
詳細については、このブログ投稿をご覧ください。
いくつかのオーバーロードがあります SelectMany
。それらの1つを使用すると、階層をトラバースしながら、親と子の関係を追跡できます。
例:次の構造があるとします。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
};
SelectMany
結合ショートカットのように機能することを理解しています。
だからあなたはできる:
var orders = customers
.Where(c => c.CustomerName == "Acme")
.SelectMany(c => c.Orders);
.SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate});
動作しません。SelectManyはリストのリストをかなりフラット化しており、結果として含まれるリストのいずれか(一度に1つだけ)を選択できます。比較のために: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リストを返します。
最初の「プロジェクト」は組織からユーザーへ、2番目はユーザーテーブルを直接クエリします。
クエリが文字列(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'
この例を考えてみましょう:
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();
つまり、「SelectMany」は複数のシーケンスにわたってフラット化および投影するため、「I」や「like」などの重複する値がquery2から削除されています。しかし、query1は文字列配列のシーケンスを返します。また、query1には2つの異なる配列(最初と2番目の要素)があるため、何も削除されません。
サブ配列オブジェクトデータを蓄積するためにSelectMany + Selectを使用する方法のもう1つの例。
電話を持っているユーザーがいるとします。
class Phone {
public string BasePart = "555-xxx-xxx";
}
class User {
public string Name = "Xxxxx";
public List<Phone> Phones;
}
次に、すべてのユーザーのすべての電話のBasePartを選択する必要があります。
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; }
}
それは私が理解する最良の方法です。
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();
乗算表の例。