ฉันได้รับการค้นหาความแตกต่างระหว่างSelect
และSelectMany
แต่ฉันไม่ได้รับสามารถที่จะหาคำตอบที่เหมาะสม ฉันต้องเรียนรู้ความแตกต่างเมื่อใช้ LINQ กับ SQL แต่ทั้งหมดที่ฉันพบคือตัวอย่างอาร์เรย์มาตรฐาน
ใครสามารถให้ตัวอย่าง LINQ กับ SQL ได้ไหม
ฉันได้รับการค้นหาความแตกต่างระหว่างSelect
และSelectMany
แต่ฉันไม่ได้รับสามารถที่จะหาคำตอบที่เหมาะสม ฉันต้องเรียนรู้ความแตกต่างเมื่อใช้ LINQ กับ SQL แต่ทั้งหมดที่ฉันพบคือตัวอย่างอาร์เรย์มาตรฐาน
ใครสามารถให้ตัวอย่าง LINQ กับ 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 });
มีหลายคนที่เลือกเช่นการดำเนินการ cross cross ใน SQLที่ใช้ผลิตภัณฑ์ cross
เช่นถ้าเรามี
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()
ให้คุณยุบลำดับหลายมิติในลักษณะที่อาจต้องใช้วินาที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 ค่อนข้างเรียบรายการรายการ - และคุณสามารถเลือกใด ๆ (แต่เพียงหนึ่งรายการในเวลาเดียว) ของรายการที่มีอยู่สำหรับผลลัพธ์ สำหรับการเปรียบเทียบ: Inner เข้าร่วมในการ 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 เดียวกันสำหรับองค์กรที่เลือก
"โครงการ" แรกจากองค์กรถึงผู้ใช้คนที่สองสอบถามตารางผู้ใช้โดยตรง
มีความชัดเจนมากขึ้นเมื่อแบบสอบถามส่งคืนสตริง (อาร์เรย์ถ่าน):
ตัวอย่างเช่นหากรายการ 'ผลไม้' มี 'แอปเปิ้ล'
'เลือก' ส่งคืนสตริง:
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'
เพียงเพื่อมุมมองทางเลือกที่อาจช่วยโปรแกรมเมอร์ที่ใช้งานบางส่วนได้:
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;
}
ตอนนี้เราต้องเลือก BaseParts ของโทรศัพท์ทั้งหมดของผู้ใช้ทั้งหมด:
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>
เช่นคอมมิวนิสต์องค์ประกอบทุกคนจะประพฤติในลักษณะเดียวกัน (เป็นคนโง่มีสิทธิเช่นเดียวของ genious หนึ่ง)
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();
ตัวอย่างตารางสูตรคูณ