Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

ความแตกต่างระหว่าง Select และ SelectMany ใน LINQ C#

ความแตกต่างหลัก

OperatorSelectSelectMany
CategoryProjectionProjection (Flattening)
Input → Output1 Element → 1 Result1 Element → IEnumerable → Flatten to 1 Sequence
Result TypeIEnumerable<TResult>IEnumerable<TResult> (Flattened)
ใช้เมื่อไหร่Mapping แบบ 1-1Flatten Nested Collections

ตัวอย่างเปรียบเทียบ


class Demo
{
    public string Name { get; set; }
    public List<string> Contents { get; set; }
    
    public static List<Demo> GetAllContents()
    {
        return new List<Demo>
        {
            new Demo { Name = "Cap", Contents = new List<string> { "Nike", "Adidas" } },
            new Demo { Name = "Shoes", Contents = new List<string> { "Nike", "Puma", "Adidas" } },
        };
    }
}

class Program
{
    static void Main()
    {
        // SELECT: คืน IEnumerable> - ยังคงโครงสร้าง Nested
        IEnumerable<List<string>> resultSelect = Demo.GetAllContents().Select(s => s.Contents);
        
        Console.WriteLine("=== Select (Nested) ===");
        foreach (List<string> list in resultSelect)
        {
            foreach (string s in list)
                Console.WriteLine(s);
        }
        
        // SELECTMANY: Flatten เป็น IEnumerable เดียว
        IEnumerable<string> resultSelectMany = Demo.GetAllContents().SelectMany(s => s.Contents);
        
        Console.WriteLine("\n=== SelectMany (Flattened) ===");
        foreach (string s in resultSelectMany)
        {
            Console.WriteLine(s);
        }
        
        Console.ReadKey();
    }
}

Output

=== Select (Nested) ===
Nike
Adidas
Nike
Puma
Adidas

=== SelectMany (Flattened) ===
Nike
Adidas
Nike
Puma
Adidas

SelectMany Overloads


// 1. Basic: TSource → IEnumerable
source.SelectMany(x => x.Children)

// 2. With Index: TSource, int → IEnumerable
source.SelectMany((x, i) => x.Children)

// 3. Result Selector: Flatten พร้อม Map Result
source.SelectMany(
    x => x.Orders,           // Collection Selector
    (x, order) => new { x.CustomerName, order.OrderId, order.Amount } // Result Selector
)

// 4. Full: Collection Selector + Result Selector + Index
source.SelectMany(
    (x, i) => x.Orders,
    (x, order, i) => new { x.CustomerName, order.OrderId, Index = i }
)

Use Cases จริง

1. Flatten List of Lists


List<List<int>> matrix = new() { new(){1,2}, new(){3,4}, new(){5} };
var flat = matrix.SelectMany(x => x); // 1,2,3,4,5

2. Query Child Collections (Master-Detail)


// Orders ของ Customer ทุกคน
var allOrders = customers.SelectMany(c => c.Orders);

// พร้อมข้อมูล Customer
var orderDetails = customers.SelectMany(
    c => c.Orders,
    (c, o) => new { c.Name, o.Id, o.Date, o.Total }
);

3. Cross Join (Cartesian Product)


var colors = new[] { "Red", "Blue" };
var sizes = new[] { "S", "M", "L" };

var combinations = colors.SelectMany(c => sizes.Select(s => $"{c}-{s}"));
// Red-S, Red-M, Red-L, Blue-S, Blue-M, Blue-L

Query Syntax


// Select
var q1 = from d in Demo.GetAllContents()
         select d.Contents;

// SelectMany (from ... from ...)
var q2 = from d in Demo.GetAllContents()
         from c in d.Contents
         select c;