Thep Excel

List.Accumulate – วนลูปสะสมค่าด้วย Accumulator Pattern

List.Accumulate เป็นฟังก์ชันสำหรับการวนลูปผ่านแต่ละ element ใน list พร้อมทั้งเก็บสถานะสะสมไว้ตลอดการทำงาน
.
โดยจะเริ่มต้นจากค่าเริ่มต้นที่กำหนด (seed value) และในแต่ละรอบของการวนลูป ฟังก์ชันจะส่งค่าสถานะปัจจุบัน (current state) พร้อมกับ element ปัจจุบันเข้าไปใน accumulator function ที่คุณกำหนดขึ้นมา เพื่อคำนวณและสร้างสถานะใหม่สำหรับรอบถัดไป
.
เมื่อวนลูปครบทุก element แล้ว ฟังก์ชันจะคืนค่าสถานะสุดท้ายกลับมา เหมาะสำหรับการคำนวณยอดสะสม (running totals) การรวมแบบกำหนดเอง (custom aggregations) และการสร้างรูปแบบ For-Next loop pattern ใน M language ครับ

=List.Accumulate(list as list, seed as any, accumulator as function) as any

By ThepExcel AI Agent
19 December 2025

Function Metrics


Popularity
6/10

Difficulty
9/10

Usefulness
8/10

Syntax & Arguments

=List.Accumulate(list as list, seed as any, accumulator as function) as any

Argument Type Required Default Description
list list Yes List ที่ต้องการวนลูปเพื่อประมวลผล แต่ละ element ใน list นี้จะถูกส่งเข้า accumulator function ทีละตัวตามลำดับ
seed any Yes ค่าเริ่มต้น (initial value) สำหรับ accumulated state ซึ่งจะถูกส่งเข้า accumulator function ในรอบแรก สามารถเป็น type ใดก็ได้ (number, text, list, record, null ฯลฯ) ขึ้นอยู่กับการใช้งาน
accumulator function Yes ฟังก์ชันที่กำหนดวิธีการคำนวณ โดยต้องรับ 2 parameters: (1) state – ค่า accumulated value ปัจจุบัน และ (2) current – element ปัจจุบันจาก list จากนั้นคืนค่า new state สำหรับรอบถัดไป รูปแบบ: (state, current) => newState

How it works

คำนวณ Running Totals และ Cumulative Values

ใช้สำหรับสร้างคอลัมน์ยอดสะสม เช่น ยอดขายสะสม, ยอดคงเหลือทางบัญชี, จำนวนสะสม โดยวนลูปผ่านแต่ละแถวและบวกค่าใหม่เข้าไปใน state ที่เก็บไว้

สร้าง For-Next Loop Pattern ใน M Language

M language ไม่มี for loop แบบดั้งเดิม แต่สามารถใช้ List.Accumulate จำลอง for loop ได้โดยการสร้าง list ของ indices และใช้ accumulator function ทำงานซ้ำตามจำนวนรอบที่กำหนด

Custom Text Concatenation แบบมีเงื่อนไข

รวมข้อความจาก list โดยสามารถกำหนดตัวคั่น (separator) แบบ conditional หรือใส่ prefix/suffix ที่แตกต่างกันในแต่ละรอบตามเงื่อนไขที่ซับซ้อน

สร้าง Process Timeline จาก Duration List

คำนวณเวลาสิ้นสุดของแต่ละ process โดยเริ่มจาก start time และบวก duration ของแต่ละ process เข้าไปทีละตัว สร้างเป็น timeline ที่แสดงเวลาเริ่มต้นของ process แต่ละตัว

Bulk Text Replace หลายคำพร้อมกัน

แทนที่หลายคำศัพท์ในข้อความโดยวนลูปผ่าน list ของคู่คำ (old, new) และใช้ Text.Replace ในแต่ละรอบเพื่อแทนที่คำเป้าหมายทีละคำ

Build Derived Lists/Sequences

สร้าง list ใหม่จาก list เดิมโดยการทำ transformation ที่ต้องอ้างอิงค่าก่อนหน้า เช่น Fibonacci sequence, moving averages หรือ conditional filtering ที่ซับซ้อน

Examples

ตัวอย่างที่ 1: ผลรวมสะสม (Running Sum) – พื้นฐาน
let Numbers = {1, 2, 3, 4, 5}, RunningSum = List.Accumulate( Numbers, 0, (state, current) => state + current ) in RunningSum
เริ่มจาก seed = 0 แล้วบวก element แต่ละตัวเข้าไปทีละตัว:
.
• รอบที่ 1: state=0, current=1 → newState=1
• รอบที่ 2: state=1, current=2 → newState=3
• รอบที่ 3: state=3, current=3 → newState=6
• รอบที่ 4: state=6, current=4 → newState=10
• รอบที่ 5: state=10, current=5 → newState=15
.
ผลลัพธ์สุดท้ายคือ 15 (ผลรวมของ 1+2+3+4+5) ครับ
Power Query Formula:

let
    Numbers = {1, 2, 3, 4, 5},
    RunningSum = List.Accumulate(
        Numbers,
        0,
        (state, current) => state + current
    )
in
    RunningSum

Result:

15

ตัวอย่างที่ 2: Bulk Text Replace – แทนที่หลายคำพร้อมกัน
let ReplacementPairs = { {"Old", "New"}, {"Bad", "Good"}, {"Slow", "Fast"} }, OriginalText = "This is Old and Bad and Slow", FinalText = List.Accumulate( Replac…
List.Accumulate วนลูปผ่าน list ของคู่คำศัพท์ {old, new} และใช้ Text.Replace แทนที่คำใน state ทีละคู่:
.
• state เริ่มต้น = "This is Old and Bad and Slow"
• รอบที่ 1: แทนที่ "Old" → "New"
• รอบที่ 2: แทนที่ "Bad" → "Good"
• รอบที่ 3: แทนที่ "Slow" → "Fast"
.
current{0} คือ element แรกของคู่ (คำเก่า) และ current{1} คือ element ที่สอง (คำใหม่) ครับ
Power Query Formula:

let
    ReplacementPairs = {
        {"Old", "New"},
        {"Bad", "Good"},
        {"Slow", "Fast"}
    },
    OriginalText = "This is Old and Bad and Slow",
    FinalText = List.Accumulate(
        ReplacementPairs,
        OriginalText,
        (state, current) => Text.Replace(state, current{0}, current{1})
    )
in
    FinalText

Result:

"This is New and Good and Fast"

ตัวอย่างที่ 3: สร้าง List ใหม่ – List of Transformed Values
let OriginalNumbers = {1, 2, 3, 4, 5}, DoubledList = List.Accumulate( OriginalNumbers, {}, (state, current) => state & {current * 2} ) in DoubledList
เริ่มจาก seed = {} (list ว่าง) แล้วนำค่าปัจจุบันคูณ 2 ไปต่อท้าย list ที่สะสมไว้ในแต่ละรอบโดยใช้ & operator:
.
• state={}, current=1 → newState={2}
• state={2}, current=2 → newState={2,4}
• state={2,4}, current=3 → newState={2,4,6}
.
ผลลัพธ์คือ list ที่มีค่าเป็น 2 เท่าของ list เดิม (แม้ List.Transform จะทำได้ง่ายกว่า แต่ตัวอย่างนี้แสดงให้เห็นว่า List.Accumulate สามารถสร้าง list ใหม่ได้) 💡
Power Query Formula:

let
    OriginalNumbers = {1, 2, 3, 4, 5},
    DoubledList = List.Accumulate(
        OriginalNumbers,
        {},
        (state, current) => state & {current * 2}
    )
in
    DoubledList

Result:

{2, 4, 6, 8, 10}

ตัวอย่างที่ 4: Process Timeline – สร้าง Timeline จาก Duration List
let ProcessDurations = { #duration(0, 1, 0, 0), // 1 ชั่วโมง #duration(0, 2, 0, 0), // 2 ชั่วโมง #duration(0, 3, 0, 0) // 3 ชั่วโมง }, StartTime = #datetime(202…
สร้าง timeline ของเวลาเริ่มต้นแต่ละ process โดยเริ่มจาก StartTime และบวก duration ทีละตัว:
.
• seed = {9:00} (list ที่มี StartTime)
• รอบที่ 1: เอา 9:00 + 1 ชม. = 10:00 → {9:00, 10:00}
• รอบที่ 2: เอา 10:00 + 2 ชม. = 12:00 → {9:00, 10:00, 12:00}
• รอบที่ 3: เอา 12:00 + 3 ชม. = 15:00 → {9:00, 10:00, 12:00, 15:00}
.
List.Last(timeList) จะดึงเวลาล่าสุดจาก list และบวก duration เพื่อหาเวลาเริ่มต้นของ process ถัดไป เหมาะสำหรับการวางแผน scheduling หรือ Gantt chart ครับ 😎
Power Query Formula:

let
    ProcessDurations = {
        #duration(0, 1, 0, 0),  // 1 ชั่วโมง
        #duration(0, 2, 0, 0),  // 2 ชั่วโมง
        #duration(0, 3, 0, 0)   // 3 ชั่วโมง
    },
    StartTime = #datetime(2025, 12, 17, 9, 0, 0),  // 9:00 น.
    Timeline = List.Accumulate(
        ProcessDurations,
        {StartTime},
        (timeList, duration) => 
            timeList & {List.Last(timeList) + duration}
    )
in
    Timeline

Result:

{
#datetime(2025, 12, 17, 9, 0, 0),
#datetime(2025, 12, 17, 10, 0, 0),
#datetime(2025, 12, 17, 12, 0, 0),
#datetime(2025, 12, 17, 15, 0, 0)
}

ตัวอย่างที่ 5: String Concatenation with Conditional Separator
let Words = {"Power", "Query", "M", "Language"}, CombinedText = List.Accumulate( Words, null, (state, current) => if state = null then current else state & " -…
รวมข้อความจาก list โดยใส่ตัวคั่น " – " ระหว่างคำ โดยใช้ conditional logic:
.
• seed = null (ไม่มีข้อความเริ่มต้น)
• รอบที่ 1: state=null, current="Power" → newState="Power"
• รอบที่ 2: state="Power", current="Query" → newState="Power – Query"
• รอบที่ 3: state="Power – Query", current="M" → newState="Power – Query – M"
.
การใช้ if condition ช่วยป้องกันไม่ให้มีตัวคั่นนำหน้าคำแรก (ซึ่ง Text.Combine ก็ทำได้เช่นกัน แต่ตัวอย่างนี้แสดงความยืดหยุ่นของ List.Accumulate ที่สามารถใส่ logic ซับซ้อนได้) ครับ
Power Query Formula:

let
    Words = {"Power", "Query", "M", "Language"},
    CombinedText = List.Accumulate(
        Words,
        null,
        (state, current) => 
            if state = null 
            then current 
            else state & " - " & current
    )
in
    CombinedText

Result:

"Power - Query - M - Language"

ตัวอย่างที่ 6: For-Next Loop Pattern – Iterate N Times
let IterationCount = 5, IndicesList = {1..IterationCount}, Result = List.Accumulate( IndicesList, "", (state, iteration) => state & "Iteration " & Text.From(ite…
จำลอง For-Next loop ใน M language โดยสร้าง list ของ indices {1..5} และใช้ List.Accumulate วนลูป 5 รอบ:
.
• IndicesList = {1, 2, 3, 4, 5}
• state เริ่มต้น = "" (empty text)
• แต่ละรอบจะเพิ่มข้อความ "Iteration N; " เข้าไป
.
เทคนิคนี้มีประโยชน์เมื่อต้องการทำงานซ้ำๆ จำนวนครั้งที่กำหนด โดยไม่สนใจค่าใน list (ใช้แค่จำนวน elements เป็นตัวกำหนดรอบ loop) ครับ
Power Query Formula:

let
    IterationCount = 5,
    IndicesList = {1..IterationCount},
    Result = List.Accumulate(
        IndicesList,
        "",
        (state, iteration) => 
            state & "Iteration " & Text.From(iteration) & "; "
    )
in
    Result

Result:

"Iteration 1; Iteration 2; Iteration 3; Iteration 4; Iteration 5; "

ตัวอย่างที่ 7: Running Balance – ยอดคงเหลือสะสมจาก Table
let Transactions = Table.FromRecords({ [Type = "Income", Amount = 1000], [Type = "Expense", Amount = -300], [Type = "Income", Amount = 500], [Type = "Expense",…
คำนวณยอดเงินคงเหลือสุดท้ายจาก list ของรายการรับ-จ่าย:
.
• AmountList = {1000, -300, 500, -200}
• balance เริ่มต้น = 0
• รอบที่ 1: 0 + 1000 = 1000
• รอบที่ 2: 1000 + (-300) = 700
• รอบที่ 3: 700 + 500 = 1200
• รอบที่ 4: 1200 + (-200) = 1000
.
หมายเหตุ: หาก balance เป็น negative จะแสดงว่าเงินไม่พอ ตัวอย่างนี้แสดงการใช้ List.Accumulate กับ real-world scenario ในการทำบัญชีครับ 💡
Power Query Formula:

let
    Transactions = Table.FromRecords({
        [Type = "Income", Amount = 1000],
        [Type = "Expense", Amount = -300],
        [Type = "Income", Amount = 500],
        [Type = "Expense", Amount = -200]
    }),
    AmountList = Transactions[Amount],
    StartingBalance = 0,
    FinalBalance = List.Accumulate(
        AmountList,
        StartingBalance,
        (balance, transaction) => balance + transaction
    )
in
    FinalBalance

Result:

1000

FAQs

List.Accumulate ต่างจาก List.Sum, List.Average อย่างไร?

List.Sum และ List.Average เป็นฟังก์ชัน specific สำหรับการรวมตัวเลขเท่านั้น
.
ในขณะที่ List.Accumulate เป็นฟังก์ชัน generic ที่ให้คุณกำหนด custom logic ผ่าน accumulator function ได้เอง ทำให้สามารถทำงานที่ซับซ้อนกว่าได้ เช่น รวมข้อความ, สร้าง list ใหม่, คำนวณแบบมีเงื่อนไข, หรือสร้าง timeline จาก duration values ครับ

accumulator function ต้องเขียนอย่างไร และ parameters คืออะไร?

accumulator function ต้องรับ 2 parameters: (1) state – ค่า accumulated value ปัจจุบัน (เริ่มจาก seed value) และ (2) current – element ปัจจุบันจาก list ที่กำลังประมวลผล
.
ฟังก์ชันต้องคืนค่า new state สำหรับรอบถัดไป รูปแบบ: (state, current) => expression ตัวอย่าง: (sum, num) => sum + num หรือ (text, word) => text & ” ” & word ครับ

สามารถใช้ List.Accumulate สร้าง running totals column ใน table ได้ไหม?

ได้ แต่ List.Accumulate คืนค่าเป็น single value (ยอดสุดท้าย) ไม่ใช่ list ของยอดสะสมแต่ละรอบ
.
หากต้องการ running totals column ควรใช้ List.Generate แทน ซึ่งสามารถสร้าง list ของ intermediate results ได้ หรือใช้ Table.AddColumn ร่วมกับ List.FirstN และ List.Sum เพื่อคำนวณ cumulative sum ของแต่ละแถวครับ

List.Accumulate ทำงานกับ empty list อย่างไร?

ถ้า list ว่าง (empty list {}) List.Accumulate จะคืนค่า seed value ทันที โดยไม่เรียก accumulator function เลย
.
เพราะไม่มี element ให้ประมวลผล ตัวอย่าง: List.Accumulate({}, 100, (s, c) => s + c) จะคืนค่า 100 ครับ

seed value จำเป็นต้องเป็น type เดียวกับ result ไหม?

ไม่จำเป็น แต่แนะนำให้ seed เป็น type เดียวกับผลลัพธ์ที่คาดหวัง เพราะ seed คือค่าเริ่มต้นของ state และ accumulator function ต้องคืนค่า new state ที่เป็น type เดียวกันในทุกรอบ
.
ตัวอย่าง: หากต้องการผลลัพธ์เป็น list ก็ใช้ seed = {} (empty list), หากต้องการ number ก็ใช้ seed = 0 หรือ null หากยอมรับค่า null ได้ครับ

List.Accumulate กับ List.Generate ต่างกันอย่างไร?

List.Accumulate คืนค่า single accumulated value (final result) ในขณะที่ List.Generate สร้าง list ของ intermediate results ทุกรอบ
.
ใช้ List.Accumulate เมื่อต้องการแค่ผลลัพธ์สุดท้าย (เช่น sum, final balance) และใช้ List.Generate เมื่อต้องการ list ของยอดสะสมทุกรอบ (เช่น running totals column) นอกจากนี้ List.Accumulate มี memory efficiency ดีกว่าเพราะเก็บแค่ state เดียว ไม่ใช่ทั้ง list ครับ 😎

จะใช้ List.Accumulate สร้าง For-Next loop ได้อย่างไร?

สร้าง list ของ indices (เช่น {1..10} สำหรับ 10 รอบ) และใช้ List.Accumulate วนลูปผ่าน list นี้
.
โดย current parameter จะเป็นหมายเลขรอบ (iteration number) และ state จะเก็บผลลัพธ์ที่สะสม ตัวอย่าง: List.Accumulate({1..5}, 0, (state, i) => state + i) จะบวกเลข 1 ถึง 5 เทคนิคนี้มีประโยชน์เมื่อต้องการ repeat operation จำนวนครั้งที่กำหนดครับ

List.Accumulate สามารถหยุดกลางคันได้ไหม (early exit)?

ไม่ได้โดยตรง List.Accumulate จะวนลูปผ่านทุก element ใน list เสมอ ไม่มีวิธี break หรือ early exit แบบ traditional loop
.
หากต้องการ conditional stopping ต้องใช้ List.Generate แทน ซึ่งสามารถกำหนด condition function เพื่อหยุดการ generate elements ได้ หรือใช้ List.FirstN กับ List.PositionOf เพื่อตัด list ก่อนส่งเข้า List.Accumulate ครับ

Resources & Related

Additional Notes

List.Accumulate เป็น Power Query function ที่ทรงพลังสำหรับการคำนวณแบบวนซ้ำ โดยใช้หลักการของ accumulator pattern (fold/reduce pattern)
.
ที่เจ๋งคือมันจะวนลูปผ่านแต่ละ element ใน list ทีละตัว พร้อมเก็บสถานะสะสมที่ถูกอัพเดทในแต่ละรอบ และส่งผลลัพธ์สุดท้ายกลับมาเป็นค่าเดียว
.
ส่วนตัวผมใช้บ่อยมากเลยครับ โดยเฉพาะตอนต้องทำ running totals หรือสร้าง For-Next loop pattern ใน M language ที่ไม่มี for loop แบบดั้งเดิม 😎

ฟังก์ชันนี้แตกต่างจากฟังก์ชันพื้นฐานทั่วไปอย่าง List.Sum หรือ List.Average ตรงที่คุณสามารถกำหนดตรรกะการคำนวณ (logic) ได้เองผ่านฟังก์ชัน accumulator ที่คุณเขียนขึ้นมา ทำให้สามารถสร้างการรวมแบบกำหนดเอง (custom aggregation) การสะสมแบบมีเงื่อนไข (conditional accumulation) หรือแม้แต่การสร้างลำดับที่มาจากการคำนวณ (derived sequences) ที่มีความซับซ้อนได้ตามต้องการ

List.Accumulate มีบทบาทสำคัญมากในการเขียน M code ระดับขั้นสูง (advanced) โดยเฉพาะอย่างยิ่งเมื่อคุณต้องการทำงานเหล่านี้:

  • คำนวณยอดสะสมแบบเรียงต่อกัน (running totals) หรือค่าสะสมสมบูรณ์ (cumulative values) จากข้อมูลในตาราง
  • สร้างรูปแบบการวนซ้ำแบบ For-Next loop pattern ใน M language ซึ่งไม่มี for loop แบบดั้งเดิม
  • ทำการแปลงข้อมูลแบบลำดับ (sequential transformation) ที่ต้องอ้างอิงค่าจากรอบก่อนหน้าในการคำนวณ
  • รวมข้อความหรือ list หลายตัวเข้าด้วยกันแบบมีเงื่อนไขที่ซับซ้อนและหลากหลาย
  • สร้างไทม์ไลน์ (timeline) หรือลำดับเวลา (sequence) จากค่าระยะเวลา (duration values) ที่มีอยู่

ฟังก์ชันนี้จะคืนค่าประเภท (type) เดียวกับค่าเริ่มต้น (seed value) ที่คุณกำหนด ซึ่งอาจเป็นตัวเลข (number) ข้อความ (text) รายการ (list) เรคคอร์ด (record) หรือประเภทอื่นๆ ก็ได้ ซึ่งทำให้ List.Accumulate มีความยืดหยุ่นสูงมากในการนำไปใช้งานกับสถานการณ์ที่หลากหลาย และเป็นเครื่องมือที่ทรงพลังสำหรับนักพัฒนาที่ต้องการควบคุมการประมวลผลข้อมูลอย่างละเอียด

Leave a Reply

Your email address will not be published. Required fields are marked *