List.Generate เป็น generator function ที่สร้าง list โดยเริ่มจากค่าเริ่มต้น (initial) วนลูปตรวจสอบเงื่อนไข (condition) สร้างค่าถัดไป (next) และ transform ผลลัพธ์ด้วย selector (optional) ทำงานคล้าย while loop ในการเขียนโปรแกรม เหมาะสำหรับสร้างลำดับวันที่, pagination API, การคำนวณทบต้น และ pattern ซับซ้อนที่ List.Numbers ทำไม่ได้
=List.Generate(initial as function, condition as function, next as function, optional selector as nullable function) as list
=List.Generate(initial as function, condition as function, next as function, optional selector as nullable function) as list
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| initial | function | Yes | Function ที่กำหนดค่าเริ่มต้น (candidate value แรก) เขียนในรูปแบบ () => value หรือ () => [record] สำหรับเก็บหลายค่า | |
| condition | function | Yes | Function ที่ตรวจสอบเงื่อนไข รับค่า candidate มาทดสอบ ถ้าผลลัพธ์เป็น true จะเพิ่มค่านั้นใน list และทำรอบต่อ ถ้า false จะหยุดทำงาน เขียนในรูปแบบ each expression (ใช้ _ อ้างอิงค่าปัจจุบัน) | |
| next | function | Yes | Function สำหรับสร้างค่า candidate ถัดไป รับค่าปัจจุบันที่ผ่านเงื่อนไขแล้ว แล้ว transform เป็นค่าถัดไป เขียนในรูปแบบ each expression (เช่น each _ + 1, each Date.AddDays(_, 1)) | |
| selector | nullable function | Optional | null | Function สำหรับ transform ค่าก่อนเพิ่มใน list ผลลัพธ์ ถ้าไม่ระบุจะใช้ค่าที่ generate ตรงๆ มีประโยชน์เมื่อใช้ record เก็บหลายค่า แต่ต้องการแสดงเฉพาะบางฟิลด์ เขียนในรูปแบบ each expression (เช่น each [fieldName]) |
สร้าง list ของวันที่ตั้งแต่วันเริ่มต้นถึงวันสิ้นสุด เพิ่มทีละ 1 วัน, ทุกสัปดาห์, ทุกเดือน หรือข้าม weekend ตาม logic ที่กำหนด
เรียก REST API ที่มี pagination โดยวนลูปเรียกทีละหน้า (page 1, 2, 3…) จนกว่า response จะไม่มี nextPageToken หรือ hasMore = false
คำนวณเงินต้นบวกดอกเบี้ยทบต้นแต่ละงวด โดยเริ่มจากเงินต้น คำนวณดอกเบี้ยรอบถัดไปจากยอดรวมก่อนหน้า วนลูปจนครบจำนวนงวดที่กำหนด
สร้างลำดับ Fibonacci โดยใช้ record เก็บสองค่าก่อนหน้า (a, b) แล้วคำนวณค่าถัดไปเป็น a + b วนลูปจนถึงขนาดที่ต้องการ
ดึงข้อมูลแบบ recursive เช่น folder structure ที่มี subfolder หลายชั้น หรือ organization hierarchy ที่ต้อง drill down จนถึง leaf node
let Countdown = List.Generate( () => 10, // เริ่มที่ 10 each _ > 0, // ทำต่อเมื่อ > 0 each _ - 1 // ลดค่าลงทีละ 1 ) in Countdownlet
Countdown = List.Generate(
() => 10, // เริ่มที่ 10
each _ > 0, // ทำต่อเมื่อ > 0
each _ - 1 // ลดค่าลงทีละ 1
)
in
Countdown
{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
let StartDate = #date(2025, 1, 1), EndDate = #date(2025, 1, 7), DateList = List.Generate( () => StartDate, // เริ่มที่ 1 ม.ค. each _let
StartDate = #date(2025, 1, 1),
EndDate = #date(2025, 1, 7),
DateList = List.Generate(
() => StartDate, // เริ่มที่ 1 ม.ค.
each _ <= EndDate, // ทำต่อถ้า <= 7 ม.ค.
each Date.AddDays(_, 1) // เพิ่มวันทีละ 1
)
in
DateList
{2025-01-01, 2025-01-02, 2025-01-03, 2025-01-04, 2025-01-05, 2025-01-06, 2025-01-07}
let OddNumbers = List.Generate( () => 1, // เริ่มที่ 1 each _ < 10, // ทำต่อถ้า < 10 each _ + 2 // เพิ่มทีละ 2 ) in OddNumberslet
OddNumbers = List.Generate(
() => 1, // เริ่มที่ 1
each _ < 10, // ทำต่อถ้า < 10
each _ + 2 // เพิ่มทีละ 2
)
in
OddNumbers
{1, 3, 5, 7, 9}
let Result = List.Generate( () => [Counter = 1, DoubleValue = 2], // เริ่มด้วย record each [Counter]let
Result = List.Generate(
() => [Counter = 1, DoubleValue = 2], // เริ่มด้วย record
each [Counter] <= 5, // ทำต่อถ้า Counter <= 5
each [ // สร้าง record ถัดไป
Counter = [Counter] + 1,
DoubleValue = [Counter] * 2
],
each [DoubleValue] // เลือกแสดงเฉพาะ DoubleValue
)
in
Result
{2, 4, 6, 8, 10}
let Fibonacci = List.Generate( () => [a = 0, b = 1, result = 0], // เริ่มด้วย 0, 1 each [result] < 10, // สร้าง 10 ตัวแรก (นับด้วย result) each [ // คำนวณค่าถัด…let
Fibonacci = List.Generate(
() => [a = 0, b = 1, result = 0], // เริ่มด้วย 0, 1
each [result] < 10, // สร้าง 10 ตัวแรก (นับด้วย result)
each [ // คำนวณค่าถัดไป
a = [b],
b = [a] + [b],
result = [result] + 1
],
each [a] // เลือกแสดงค่า a
)
in
Fibonacci
{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}
let AllPages = List.Generate( () => [PageNumber = 1, HasMore = true], // เริ่มหน้า 1 each [HasMore] = true, // ทำต่อถ้ายังมีหน้าถัดไป each [ // จำลองการเรียก AP…let
AllPages = List.Generate(
() => [PageNumber = 1, HasMore = true], // เริ่มหน้า 1
each [HasMore] = true, // ทำต่อถ้ายังมีหน้าถัดไป
each [ // จำลองการเรียก API
PageNumber = [PageNumber] + 1,
HasMore = [PageNumber] < 5 // มี 5 หน้าทั้งหมด
],
each "Page " & Text.From([PageNumber]) // สร้าง label
)
in
AllPages
{"Page 1", "Page 2", "Page 3", "Page 4", "Page 5"}
List.Numbers สร้างลำดับตัวเลขตาม pattern คงที่ (start, count, increment) เหมาะกับลำดับเลขเรียงง่ายๆ เช่น {1, 2, 3} หรือ {0, 10, 20, 30} แต่ List.Generate ให้คุณควบคุม logic การสร้างค่าได้เองทั้งหมดผ่าน function parameters ทำให้สร้าง pattern ซับซ้อนได้ เช่น Fibonacci, compound growth, หรือ conditional sequence ที่ List.Numbers ทำไม่ได้
เพราะ List.Generate ต้องการ function type สำหรับทุก parameter ไม่ใช่แค่ค่าตายตัว () => value เป็น syntax ของ anonymous function ใน M language ที่ไม่รับ parameter และ return ค่าคงที่ วิธีนี้ทำให้ Power Query สามารถเรียก function เมื่อต้องการได้ แทนที่จะ evaluate ค่าตั้งแต่ตอนเริ่ม ซึ่งสอดคล้องกับ lazy evaluation pattern ของ Power Query
each เป็น shorthand syntax ของ M language สำหรับเขียน anonymous function ที่รับ parameter เดียว โดย _ คือ placeholder แทนค่า parameter นั้น เช่น each _ > 0 เทียบเท่ากับ (x) => x > 0 ใช้ each กับ condition, next, และ selector parameters ของ List.Generate เพราะ function เหล่านี้รับค่า candidate หรือ item เดียวเป็น input ส่วน initial ใช้ () => value เพราะไม่รับ parameter
Selector ช่วยให้คุณ transform ค่าก่อนเพิ่มเข้า list ผลลัพธ์ มีประโยชน์มากเมื่อใช้ record structure เก็บหลายค่า (เช่น [x = 1, y = 2]) แต่ต้องการแสดงเฉพาะบางฟิลด์ (เช่น each [y] จะได้เฉพาะค่า y) หรือต้องการคำนวณค่าใหม่จากหลายฟิลด์ (เช่น each [Price] * [Quantity]) ถ้าไม่ระบุ selector จะใช้ค่าที่ generate ตรงๆ
Power Query ไม่มี hard limit สำหรับจำนวนรอบของ List.Generate แต่ถ้าวนลูปเกินไปจะทำให้ performance ช้าและอาจเกิด memory issue ดังนั้นควรมีเงื่อนไข (condition function) ที่รับประกันได้ว่าจะหยุดในที่สุด หลีกเลี่ยง infinite loop โดยตรวจสอบให้มั่นใจว่าค่า candidate จะทำให้เงื่อนไขเป็น false ได้ในที่สุด เช่นใช้ counter หรือเช็คค่า null
ใช้ record เก็บ URL หรือ pageToken พร้อมกับข้อมูลที่ดึงมา เช่น () => [url = “api.com/data?page=1”, data = {}] ใน next function เรียก Web.Contents กับ URL ปัจจุบัน parse response เพื่อหา nextPageUrl และ append data ที่ได้เข้า list ใน condition ตรวจสอบว่า nextPageUrl มีค่าหรือไม่ (each [nextPageUrl] null) ใน selector ดึงเฉพาะ data ออกมา (each [data]) แล้วใช้ List.Combine รวมทุกหน้าเป็น table เดียว
ฟังก์ชัน List.Generate ใน Power Query เป็นเครื่องมือสำหรับสร้าง list แบบ dynamic โดยใช้ generator pattern ซึ่งคล้ายกับการวนลูป while loop ในภาษาโปรแกรมมิ่ง ฟังก์ชันนี้ทำงานโดยเริ่มจากค่าเริ่มต้น (initial value) แล้ววนลูปตรวจสอบเงื่อนไข (condition) และสร้างค่าถัดไป (next value) จนกว่าเงื่อนไขจะเป็นเท็จ
ฟังก์ชันนี้มีประโยชน์อย่างมากในการสร้างข้อมูลที่มี pattern ซับซ้อน เช่น การสร้างลำดับวันที่ระหว่างช่วงเวลา การเรียก API แบบ pagination ที่ต้องวนลูปหลายหน้า หรือการคำนวณแบบทบต้นที่ค่าแต่ละรอบขึ้นอยู่กับค่าก่อนหน้า โดย List.Generate สามารถทำงานกับ record structure เพื่อเก็บสถานะหลายตัวแปรพร้อมกันได้
จุดเด่นของ List.Generate คือความยืดหยุ่นสูง เพราะคุณสามารถกำหนด logic การทำงานได้เองทั้งหมดผ่าน 4 function parameters ซึ่งแตกต่างจาก List.Numbers หรือ List.Dates ที่มี pattern การสร้างค่าแบบตายตัว นอกจากนี้ยังมี optional selector parameter ที่ช่วยให้คุณ transform ค่าผลลัพธ์ก่อนส่งออกมาได้อีกด้วย