Sự khác biệt giữa Chọn và Chọn Nhiều


1074

Tôi đã tìm kiếm sự khác biệt giữa SelectSelectManynhưng tôi không thể tìm thấy câu trả lời phù hợp. Tôi cần tìm hiểu sự khác biệt khi sử dụng LINQ To SQL nhưng tất cả những gì tôi tìm thấy là các ví dụ mảng tiêu chuẩn.

Ai đó có thể cung cấp một ví dụ LINQ To SQL không?


8
bạn có thể nhìn vào mã cho SelectMany với một chức năng, hoặc với hai chức năng referencesource.microsoft.com/#System.Core/System/Linq/...
barlop

1
Nếu bạn quen thuộc với Kotlin, nó có các triển khai khá giống nhau cho các bộ sưu tập dưới dạng map aka C # Chọn và FlatMap aka C # SelectMany. Về cơ bản các hàm mở rộng thư viện std của Kotlin cho các bộ sưu tập có sự tương đồng với thư viện C # Linq.
Arsenius

Câu trả lời:


1622

SelectManylàm phẳng các truy vấn trả về danh sách các danh sách. Ví dụ

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

Demo trực tiếp trên .NET Fiddle


1
Câu hỏi liên quan về lồng nhau ChọnMany để làm phẳng cấu trúc phân cấp lồng nhau.
Hạt đậu đỏ

1
Để hiểu resultSelector hơn dưới đây liên kết giúp blogs.interknowlogy.com/2008/10/10/...
jamir

Thêm một bản demo với kết quả từ phụ huynh: dotnetfiddle.net/flcdCC
Evgeniy Kosjakov

cảm ơn bạn đã liên kết fiddle!
Aerin

197

Chọn nhiều giống như hoạt động nối chéo trong SQL trong đó nó lấy sản phẩm chéo.
Ví dụ nếu chúng ta có

Set A={a,b,c}
Set B={x,y}

Chọn nhiều có thể được sử dụng để có được bộ sau đây

{ (x,a) , (x,b) , (x,c) , (y,a) , (y,b) , (y,c) }

Lưu ý rằng ở đây chúng tôi lấy tất cả các kết hợp có thể có thể được thực hiện từ các phần tử của tập A và tập B.

Dưới đây là một ví dụ LINQ bạn có thể thử

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

hỗn hợp sẽ có các yếu tố sau trong cấu trúc phẳng như

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}

4
Tôi biết điều này đã cũ, nhưng tôi muốn cảm ơn bạn vì điều này, nó đã cứu tôi rất nhiều! :) Cũng có thể hữu ích khi có một tham chiếu đến các mã đó: stackoverflow.com/questions/3479980/ Chúc mừng!
dùng3439065

4
ChọnMany không phải được sử dụng như thế. Nó có một tùy chọn để chỉ có một chức năng quá.
barlop

2
Tôi không biết nếu đó là đúng khi nói rằng đây là cách SelectMany . Thay vào đó, đây là một cách SelectManycó thể được sử dụng, nhưng thực tế không phải là cách sử dụng thông thường.
Dave Cousineau

1
Đây là câu trả lời đơn giản nhất để tôi hiểu.
Chaim Eliyah

Sẽ tốt hơn nếu bạn cũng chứng minh Wheređiều kiện sau ChọnMany
Nitin Kt

126

nhập mô tả hình ảnh ở đây

var players = db.SoccerTeams.Where(c => c.Country == "Spain")
                            .SelectMany(c => c.players);

foreach(var player in players)
{
    Console.WriteLine(player.LastName);
}
  1. De Gea
  2. Alba
  3. Costa
  4. Biệt thự
  5. Xe buýt

...


9
dữ liệu ví dụ tuyệt vời
ben_mj

2
bạn có thể thêm một ví dụ để chọn để hoàn thành câu trả lời này không :)
Harry

73

SelectMany()cho phép bạn thu gọn một chuỗi nhiều chiều theo cách mà nếu không yêu cầu thứ hai Select()hoặc vòng lặp.

Thêm chi tiết tại bài viết blog này .


Nhưng kiểu trả về đầu tiên của trẻ em Kiểu con thứ hai là kiểu trả về của cha mẹ? Thật ra tôi hơi bối rối, bạn sẽ mở nó ra thêm một chút chứ?
Tarik

Cách khác, thực sự. Thứ hai sẽ hoàn toàn san phẳng hệ thống phân cấp của vô số, để bạn đưa trẻ em trở lại. Hãy thử bài viết tại liên kết tôi đã thêm, xem nếu điều đó giúp.
Michael Petrotta

Cái đầu tiên không có vẻ hợp pháp. Tôi nghĩ rằng các poster đã tự nhầm lẫn. Người thứ hai sẽ trả lại vô số cha mẹ.
mqp

Cảm ơn, thực sự vâng các ví dụ khá khó hiểu :) nhưng cảm ơn lần nữa vì đã cố gắng giúp tôi.
Tarik

37

Có một số quá tải đến SelectMany. Một trong số chúng cho phép bạn theo dõi bất kỳ mối quan hệ nào giữa cha mẹ và con cái trong khi đi qua hệ thống phân cấp.

Ví dụ : giả sử bạn có cấu trúc sau : League -> Teams -> Player.

Bạn có thể dễ dàng trả lại một bộ sưu tập phẳng của người chơi. Tuy nhiên, bạn có thể mất bất kỳ tham chiếu nào đến đội mà người chơi là một phần của.

May mắn là có một quá tải cho mục đích như vậy:

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

Ví dụ trước được lấy từ blog IK của Dan . Tôi thực sự khuyên bạn nên xem nó.


19

Tôi hiểu SelectManyđể làm việc như một phím tắt tham gia.

Vì vậy, bạn có thể:

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

Ví dụ được cung cấp hoạt động, nhưng SelectMany không hoạt động chính xác như tham gia. Phép nối cho phép "sử dụng" bất kỳ trường nào của bảng gốc cộng với bất kỳ trường nào của bảng đã nối. Nhưng ở đây bạn phải chỉ định một đối tượng của một danh sách được đính kèm vào bảng gốc. Ví dụ, .SelectMany(c => new {c.CompanyName, c.Orders.ShippedDate});sẽ không hoạt động. SelectMany khá làm phẳng danh sách các danh sách - và bạn có thể chọn bất kỳ (nhưng chỉ một danh sách một lần) trong danh sách được chứa cho kết quả. Để so sánh: Tham gia nội bộ trong Linq .
Matt

13

Chọn là phép chiếu một-một đơn giản từ phần tử nguồn sang phần tử kết quả. Chọn- Nhiều được sử dụng khi có nhiều từ trong mệnh đề truy vấn: mỗi phần tử trong chuỗi ban đầu được sử dụng để tạo một chuỗi mới.


7

Một số SelectMany có thể không cần thiết. Dưới 2 truy vấn cho kết quả tương tự.

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

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

Đối với mối quan hệ 1-Nhiều,

  1. nếu Bắt đầu từ "1", thì ChọnMany là cần thiết, nó sẽ làm phẳng nhiều thứ.
  2. nếu Bắt đầu từ "Nhiều", thì không cần phải chọn. ( vẫn có thể lọc từ "1" , điều này cũng đơn giản hơn so với truy vấn nối tiêu chuẩn bên dưới)

from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o

4

Không cần quá kỹ thuật - cơ sở dữ liệu với nhiều Tổ chức, mỗi tổ chức có nhiều Người dùng: -

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

cả hai trả về cùng một danh sách ApplicationUser cho Tổ chức đã chọn.

Các "dự án" đầu tiên từ Tổ chức đến Người dùng, lần thứ hai truy vấn trực tiếp vào bảng Người dùng.


3

Rõ ràng hơn khi truy vấn trả về một chuỗi (một mảng char):

Ví dụ: nếu danh sách 'Trái cây' chứa 'quả táo'

'Chọn' trả về chuỗi:

Fruits.Select(s=>s) 

[0]: "apple"

'ChọnMany' làm phẳng chuỗi:

Fruits.SelectMany(s=>s)

[0]: 97  'a'
[1]: 112 'p'
[2]: 112 'p'
[3]: 108 'l'
[4]: 101 'e'

2

Chỉ cho một cái nhìn thay thế có thể giúp một số lập trình viên chức năng ngoài kia:

  • Selectmap
  • SelectManybind(hoặc flatMapcho người Scala / Kotlin của bạn)

2

Xem xét ví dụ này:

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

Vì vậy, khi bạn thấy các giá trị trùng lặp như "I" hoặc "like" đã bị xóa khỏi truy vấn2 vì "Chọn" làm phẳng và các dự án trên nhiều chuỗi. Nhưng query1 trả về chuỗi các chuỗi chuỗi. và vì có hai mảng khác nhau trong query1 (phần tử thứ nhất và thứ hai), nên không có gì bị xóa.


có lẽ tốt hơn bây giờ bao gồm .Distinc () ở cuối và nói rằng nó xuất ra "I" "như" "cái gì" "tôi" "thích" "tôi" "thích" "cái gì" "bạn" "thích"
Giáo sư

1

Thêm một ví dụ nữa về cách ChọnMany + Chọn có thể được sử dụng để tích lũy dữ liệu đối tượng mảng phụ.

Giả sử chúng ta có người dùng với điện thoại của họ:

class Phone { 
    public string BasePart = "555-xxx-xxx"; 
}

class User { 
    public string Name = "Xxxxx";
    public List<Phone> Phones; 
}

Bây giờ chúng tôi cần chọn BaseParts của tất cả điện thoại của tất cả người dùng:

var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();

Mà bạn nghĩ là tốt hơn? Của bạn hoặcusersArray.SelectMany(ua => ua.Phones.Select(p => p.BasePart))
Michael hay nhất

-1

Dưới đây là một ví dụ mã với một bộ sưu tập nhỏ được khởi tạo để thử nghiệm:

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

-2

Các SelectManygõ phương pháp ngã một IEnumerable<IEnumerable<T>>thành IEnumerable<T>, giống như chủ nghĩa cộng sản, mỗi phần tử được cư xử theo cách tương tự (một chàng trai ngu ngốc có cùng quyền lợi của mộ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" }

-5

Đó là cách tốt nhất để hiểu tôi nghĩ.

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

Ví dụ bảng nhân.


4
Chỉ khi ý nghĩa của "tốt nhất" đã thay đổi đáng kể.
Vahid Amiri

2
Vì vậy, đây là cách tốt nhất bạn nghĩ ?? Vậy thì cách suy nghĩ khó khăn là gì ??
Syed Ali
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.