พระคัมภีร์การใช้คำสั่ง LINQ
🤔 คำสั่งของ LINQ ที่ได้ใช้บ่อยๆมีไรบ้างนะ
บทความนี้เป็นบทความที่แยกออกมาจากเรื่อง LINQ ซึ่งเป็นหนึ่งในคำสั่งเทพเจ้าของสาย .NET ซึ่งมันจะทำให้ developer ทำงานได้สบายลงแบบฝุดๆ ดังนั้นใครยังไม่รู้เรื่อง LINQ ให้กลับไปอ่านบทความนี้ก่อนเน่อ Saladpuk - LINQ 101
Filtering Data
Where - เป็นการเลือกเอาเฉพาะข้อมูลที่เราสนใจออกมา เช่น มี data source เป็นเลข 1~100 แล้วต้องการเอาเฉพาะเลขที่ 5 และ 7 หารลงตัวออกมา ก็จะเขียนออกมาได้เป็นแบบนี้
Projection Operations
Select - เป็นการเลือกว่า data source ที่เราไปดึงข้อมูลมา เราจะดัดแปลงแก้ไข หรือ เลือกเอาเฉพาะข้อมูลบางส่วนออกมาใช้
เช่นมี collection เป็นเลข 1~5 ตอนที่เราจะเอามาทำงานด้วยเราจะแก้ให้มันถูก คูณด้วย 10 ก่อนค่อยเอามาใช้งาน ก็จะเขียนได้แบบนี้
หรือ จะให้มันเปลี่ยนเป็นข้อมูลอีกประเภทนึงเลยก็ได้
ส่วนถ้าข้อมูลใน data source มันวุ่นวายเกินไป เราก็สามารถเลือกแค่บางส่วนของมันมาใช้ก็ได้นะ เช่น เราอยากได้แค่ Name ที่อยู่ใน collection มาใช้เท่านั้น ก็เขียนเป็นแบบนี้ได้
SelectMany - เป็นการเลือกเข้าไปถึงหน่วยย่อยของ collection ที่ซ้อนภายใน collection อีกทีนึง
แนะนำให้อ่าน คำสั่ง SelectMany สำหรับคนที่พึ่งหัดใช้ LINQ อาจจะ งงๆ หน่อยแต่ถ้าเราได้ทำงานร่วมกับพวก collection ซ้อน collection แล้วล่ะก็ควรจะทำความเข้าใจมันเอาไว้นะ ซึ่งอ่านได้จากลิงค์นี้เลย Microsoft document - Projection Operations
Element Operations
ในบางทีเราอยากจะทำงานกับข้อมูลแค่ตัวใดตัวหนึ่งหรือส่วนหนึ่งที่อยู่ใน collection เราก็สามารถใช้คำสั่งที่อยู่ด้านล่างได้ เช่น เรามี data source ที่มีข้อมูลเป็นเลข 1~100
First - เอาเฉพาะตัวแรกออกมา
FirstOrDefault - เหมือนกับ First ทุกประการ ต่างกันแค่ถ้ามันดึงค่าออกมาไม่ได้มันจะส่งค่า default ของ data type นั้นๆกลับมา
Last - เอาเฉพาะตัวสุดท้ายออกมา
LastOrDefault - เหมือนกับ Last ทุกประการ ต่างกันแค่ถ้ามันดึงค่าออกมาไม่ได้มันจะส่งค่า default ของ data type นั้นๆกลับมา
ElementAt - เป็นการดึงค่าที่อยู่ใน index ที่กำหนดออกมา
ElementAtOrDefault - เหมือนกับ ElementAt ทุกประการ ต่างกันแค่ถ้ามันดึงค่าออกมาไม่ได้มันจะส่งค่า default ของ data type นั้นๆกลับมา
อันตราย ถ้า data source เป็น collection ว่าง แล้วไปใช้คำสั่งพวก First, Last, ElementAt มันจะทำให้เกิด Exception ได้ครับ ดังนั้นโดยปรกติผมจะแนะนำให้ใช้คำสั่ง FirstOrDefault, LastOrDefault, ElementAtOrDefault แทนมากกว่า เพราะค่า overhead ในการจัดการกับ error มันสูงกว่าครับ
Partitioning Data
เวลาที่เราทำงานกับ data source ปริมาณมากๆ เราสามารถที่จะทำการแบ่งข้อมูลออกเป็นส่วนๆ เพื่อให้ง่ายในการทำงานได้ เช่น มี collection ตัวเลข 1~100 อยู่ตามด้านล่าง
Take - เป็นการสั่งให้ดึงข้อมูลจาก data source ออกมาเท่าที่เรากำหนดไว้ เช่น เราอยากดึงข้อมูลมาแค่ 5 ตัวแรกก่อน เราก็จะเขียนได้ว่า
TakeLast - เหมือนกับ Take แต่จะดึงมาจากด้านหลังสุด เช่น อยากจะดึงข้อมูล 5 ตัวจากด้านหลังสุดออกมา
TakeWhile - เป็นการสั่งให้มันดึงข้อมูลจาก data source ออกมาเรื่อยๆจนกว่าจะเจอตัวแรกที่ทำให้เงื่อนไขไม่เป็นจริง เช่น ให้ดึงมาเรื่อยๆถ้าเลขที่ดึงมามันยังน้อยกว่า 8
Skip - สั่งให้ข้ามข้อมูลเท่ากับที่เรากำหนด เช่น เราต้องการข้ามข้อมูล 4 ตัวแรกไป
SkipLast - เหมือนกับ Skip ต่างกันแค่มันจะข้ามเฉพาะตัวด้านหลังสุด เช่น อยากจะข้ามข้อมูล 4 ตัวสุดท้ายไป
SkipWhile - เป็นการสั่งให้มันข้ามข้อมูลไปเรื่อยๆ ถ้าเงื่อนไขยังเป็นจริงอยู่ และจะหยุดข้ามเมื่อเจอข้อมูลตัวแรกที่ไม่ตรงเงื่อนไข เช่น อยากจะข้ามไปเรื่อยๆจนกว่าจะเจอตัวแรกที่มากกว่า 50
Set Operations
เราสามารถทำงานกับ data source ที่เป็น 2 กลุ่มให้มาทำงานร่วมกันได้ 3 แบบคือ
เช่นเรามีข้อมูลกลุ่ม a กับกลุ่ม b เป็นแบบนี้
Intersect - ตามรูปเลยคือ เอาเฉพาะที่มันเหมือนกันออกมา
Union - ตามรูปเลยคือ เอาทั้งสองกลุ่มมารวมกัน
Except - ตามรูปเลยคือ เอาเฉพาะของที่ไม่ซ้ำกับอีกกลุ่มออกมา
Distinct - เป็นการตัดตัวซ้ำทิ้ง
Sorting Data
การเรียงลำดับเราทำได้ 3 แบบ น้อยไปมาก
มากไปน้อย
และ กลับด้านข้อมูล
เช่นเรามี data source เป็นแบบนี้
OrderBy - เรียงลำดับจากน้อยไปมาก หรือถ้าเป็นตัวอักษรจะเป็นการเรียงจาก a~Z
OrderByDescending - เรียงลำดับจากมากไปน้อย
Reverse - เรียงลำดับแบบกลับด้าน ขวาไปซ้าย แทน
ThenBy และ ThenByDescending - แต่ถ้าข้อมูลมีความซับซ้อนมากขึ้น เราสามารถกำหนดความสำคัญในการเรียงลำดับได้ด้วย เช่น เรียงลำดับจากคะแนนน้อยไปมาก แต่ถ้าคะแนนเท่ากันให้เรียงจากชื่อตามลำดับตัวอักษรก็จะเขียนแบบนี้ได้
Quantifier Operations
เราสามารถหาผลลัพท์จากข้อมูลใน collection ได้เช่น มีบางตัวไหม? หรือ ทุกตัวเป็นแบบนี้ไหม? อาจจะฟังแล้ว งงๆ ไปดูตัวอย่างเลยดีกว่า โดยสมมุติว่าผมมี data source เป็นแบบนี้
Any - ถามว่ามีซักตัวไหมที่เป็นแบบนี้ เช่น อยากรู้ว่ามีซักตัวไหมใน collection ที่มีค่ามากกว่า 9 ก็สามารถเขียนเป็น
All - ถามว่าทุกตัวเป็นแบบนี้หรือเปล่า เช่น อยากเช็คว่าทุกตัวใน collection มากกว่า 5 หรือเปล่า
Contains - ถามว่าภายในนั้นมีตัวนี้อยู่หรือเปล่า เช่น collection นั้นมีเลข 8 อยู่ในนั้นหรือเปล่า
Grouping Data
GroupBy - สั่งให้มันจัดกลุ่มของข้อมูลได้ เช่น มี collection ของคนหลายๆคน แล้วเราอยากให้จัดกลุ่มคนตามอายุ เราก็จะเขียนได้ว่า
Generation Operations
ถ้าเราต้องการสร้างข้อมูลที่เป็น collection ขึ้นมาแบบง่ายๆ เราก็สามารถใช้ LINQ ช่วยสร้างได้
Range - สร้างชุดตัวเลขออกมา เช่น อยากได้ collection ตัวเลขตั้งแต่ 1 ถึง 100
Empty - สร้าง collection ว่างออกมา เช่น เราอยากได้ collection ของตัวเลข แต่ไม่ต้องมีข้อมูลอะไรอยู่ข้างในนะ
DefaultIfEmpty - ถ้าเราต้องไปทำงานกับ collection ตัวเลขซักตัว แต่ถ้า collection นั้นมันเป็นค่าว่าง เราจะกำหนดค่า 9 ให้มันไปใช้แทน
Repeat - สร้างชุดข้อมูลซ้ำๆกันออกมา เช่น อยากได้ collection เลข 5 ซ้ำกัน 3 ตัว ก็เขียนแบบนี้ได้
Converting Data Types
เราสามารถแปลง data source ของเราจาก data type นึงไปยังอีก data type นึงก็ได้นะ เช่น มีข้อมูล collection เลข 1~5 ตามนี้
AsEnumerable - แปลงให้มันกลับมาเป็น IEnumerable<T> เอาไว้ช่วยแปลงจาก collection อะไรก็ตามให้กลับมาสู่ base class ของกลุ่ม collection
AsQueryable - แปลงให้คำสั่งทั้งหมดยังเป็นแค่ Query เท่านั้น ซึ่งใช้ได้ดีตอนที่ทำงานร่วมกับ database เพราะเราจะได้ส่งแต่คำสั่งไปประมวลผลที่ database เท่านั้นไม่ได้ส่งข้อมูลปริมาณมหาศาลกลับมาถล่มที่ client
Cast - แปลงข้อมูลจาก data source ให้กลายเป็น data type ที่กำหนด
OfType - เลือกเอาเฉพาะ data type ที่ตรงกับที่กำหนด
ToArray - แปลงให้ collection นั้นๆกลายเป็น Array
ToList - แปลงให้ collection นั้นๆกลายเป็น List
ToDictionary - แปลงให้ collection นั้นๆกลายเป็น Dictionary<K, V> เช่นทำการจัดกลุ่มว่าใครเรียนอยู่ห้องไหนบ้าง แล้วทำการไปสร้างเป็น dictionary
Concatenation Operations
Concate - เป็นการเอา 2 collection มาต่อกันแบบดื้อๆเลย
Aggregation Operations
เป็นกลุ่มคำสั่งที่ได้ผลลัพท์กลับมาเลย และเป็นการทำงานแบบ Imperative เช่นมี data source เป็นเลข 1~10 ตามนี้
Sum - หาผลรวม
Average - หาค่าเฉลี่ย
Max - หาค่าสูงสุด
Min - หาค่าต่ำสุด
Count - นับว่าภายใน data source มีข้อมูลอยู่ทั้งหมดเท่าไหร่
Aggregate - นำข้อมูลทั้ง collection มาดำเนินการแบบต่อเนื่องกัน
แนะนำให้อ่าน คำสั่ง Aggregate ถ้าเราใช้เป็นจริงๆมันทรงพลังมากเลยนะ ลองศึกษาเพิ่มเติมได้จากลิงค์นี้เบย Microsoft document - Aggregation
บทสรุป Deferred vs Imperative
จากคำสั่งทั้งหมดที่เขียนมาเป็นตัวอย่าง สุดท้ายการทำงานของมันก็จะตกมาอยู่ในกลุ่ม 3 กลุ่มนั่นเองคือ
ทำงานโดยทันที Immediate
ไม่ทำงานจนกว่าจะเรียกใช้ Deferred
ดึงข้อมูลทั้งหมดมาก่อนค่อยทำงาน Non-Streaming
ค่อยทะยอยดึงข้อมูลมาเรื่อยๆ Streaming
Operators | Return Type | Immediate | Deferred Streaming | Deferred Non-Streaming |
TSource | X | |||
X | ||||
X | ||||
X | ||||
Single numeric value | X | |||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
TSource | X | |||
TSource | X | |||
X | ||||
X | X | |||
TSource | X | |||
TSource | X | |||
X | ||||
X | X | |||
X | X | |||
X | X | |||
TSource | X | |||
TSource | X | |||
X | ||||
Single numeric value, TSource, or TResult | X | |||
Single numeric value, TSource, or TResult | X | |||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
X | ||||
TSource | X | |||
TSource | X | |||
X | ||||
X | ||||
Single numeric value | X | |||
X | ||||
X | ||||
X | ||||
X | ||||
TSource array | X | |||
X | ||||
X | ||||
X | ||||
X | ||||
X |
Last updated