式編程到Excel/WPS實(shí)戰(zhàn))
最近在寫數(shù)據(jù)處理腳本時(shí)總被兩個(gè)問(wèn)題糾纏一個(gè)是reduce到底比循環(huán)強(qiáng)在哪另一個(gè)是遞歸寫起來(lái)很爽但一不小心棧溢出。后來(lái)在 Excel/WPS 里寫公式時(shí)發(fā)現(xiàn)LAMBDA、REDUCE也開(kāi)始普及了這兩種思維在表格里居然也能用。于是想寫一篇系統(tǒng)點(diǎn)的筆記把Reduce、Lambda、遞歸、終止條件、循環(huán)深度和底層邏輯放在一起講清楚順便聊一聊在 Excel/WPS 編程中的實(shí)戰(zhàn)玩法。這篇文章適合三類讀者剛開(kāi)始學(xué) Python / JavaScript 函數(shù)式編程對(duì)reduce和遞歸一知半解的初學(xué)者。在 Excel / WPS 中使用LAMBDA、REDUCE、遞歸自定義函數(shù)做表格處理的辦公自動(dòng)化用戶。想梳理清楚“迭代 vs 遞歸 vs 歸約”底層關(guān)系的中級(jí)開(kāi)發(fā)者。讀完你會(huì)得到一份完整的知識(shí)地圖概念怎么理解、代碼怎么寫、坑在哪、性能怎么取舍、Excel/WPS 場(chǎng)景怎么落地。1. 函數(shù)式編程中的 Lambda 與遞歸基礎(chǔ)1.1 什么是 Lambda 表達(dá)式Lambda 這個(gè)詞最早源于數(shù)學(xué)中的 λ 演算Lambda Calculus它描述的是一個(gè)“匿名函數(shù)”——沒(méi)有名字只有參數(shù)和返回值可以被當(dāng)作值傳遞。在 Python 中一個(gè)普通函數(shù)可以寫成這樣def add(x, y): return x y用 Lambda 表示就是add lambda x, y: x y print(add(2, 3)) # 輸出 5這里的lambda x, y: x y就是一個(gè)匿名函數(shù)它不占用函數(shù)名可以隨時(shí)創(chuàng)建、傳遞、調(diào)用。在 Java 中Lambda 表達(dá)式長(zhǎng)這樣BiFunctionInteger, Integer, Integer add (x, y) - x y; System.out.println(add.apply(2, 3)); // 輸出 5在 Excel/WPS 中新版的LAMBDA函數(shù)也是同一個(gè)思想LAMBDA(x, y, x y)(2, 3)運(yùn)行結(jié)果同樣是 5。所以Lambda 的核心價(jià)值不是“省掉一個(gè)函數(shù)名”而是讓函數(shù)成為“一等公民”可以像變量一樣參與運(yùn)算。它是后面講reduce、遞歸式的函數(shù)組合的基礎(chǔ)。1.2 什么是遞歸遞歸是一種“自己調(diào)用自己”的解決問(wèn)題方式。一個(gè)遞歸函數(shù)通常包含兩部分遞歸調(diào)用把大問(wèn)題拆成同類型的小問(wèn)題。終止條件小問(wèn)題小到可以直接返回結(jié)果的邊界情況??匆粋€(gè)最簡(jiǎn)單的遞歸例子計(jì)算 n 的階乘。def factorial(n): if n 1: # 終止條件 return 1 return n * factorial(n - 1) # 遞歸調(diào)用當(dāng)n5時(shí)執(zhí)行過(guò)程是factorial(5) 5 * factorial(4) 5 * 4 * factorial(3) 5 * 4 * 3 * factorial(2) 5 * 4 * 3 * 2 * factorial(1) 5 * 4 * 3 * 2 * 1 120可以看到遞歸讓代碼非常貼近數(shù)學(xué)定義易于理解。但問(wèn)題是每一層調(diào)用都會(huì)占用一塊調(diào)用棧內(nèi)存層次太深就容易爆棧。1.3 終止條件為什么是遞歸的“命門”很多初學(xué)遞歸的人最容易犯的錯(cuò)誤就是“忘了終止條件”或者“終止條件寫錯(cuò)”。比如下面這段代碼def bad_recursive(n): return n bad_recursive(n 1)這個(gè)函數(shù)沒(méi)有終止條件會(huì)一直遞歸下去直到 Python 拋出RecursionError。所以在寫任何遞歸時(shí)請(qǐng)先回答三個(gè)問(wèn)題最小的問(wèn)題怎么直接解決每次遞歸問(wèn)題規(guī)模是否在變小是否一定能到達(dá)最小問(wèn)題沒(méi)有終止條件的遞歸就是死循環(huán)只是它死得比較體面叫“棧溢出”。2. Reduce 到底在做什么2.1 Reduce 的來(lái)源與本質(zhì)reduce是函數(shù)式編程中的經(jīng)典高階函數(shù)在 Python 中位于functools模塊在 JavaScript 中是數(shù)組方法Array.prototype.reduce在 Java Stream 中也有reduce方法。它的本質(zhì)是把一組數(shù)據(jù)通過(guò)一個(gè)“累計(jì)函數(shù)”逐步合并成一個(gè)值。以 Python 為例from functools import reduce result reduce(lambda acc, x: acc x, [1, 2, 3, 4, 5], 0) print(result) # 輸出 15這段代碼的含義是初始累計(jì)值acc 0。把列表中的第一個(gè)元素1和acc傳入lambda得到0 1 1。再把結(jié)果1和第二個(gè)元素2相加得到3。依次執(zhí)行直到列表遍歷完。過(guò)程可以展開(kāi)為acc 0 acc acc 1 # 1 acc acc 2 # 3 acc acc 3 # 6 acc acc 4 # 10 acc acc 5 # 15這里 Lambda 表達(dá)式lambda acc, x: acc x就是歸約規(guī)則。reduce只是負(fù)責(zé)“遍歷數(shù)據(jù)、保存中間狀態(tài)、調(diào)用歸約規(guī)則”的調(diào)度器。2.2 Reduce 與循環(huán)的對(duì)應(yīng)關(guān)系reduce本質(zhì)上是把for循環(huán)封裝成了一個(gè)函數(shù)。下面兩種寫法是等價(jià)的普通循環(huán)def sum_with_loop(data): acc 0 for x in data: acc acc x return acc使用 reducefrom functools import reduce def sum_with_reduce(data): return reduce(lambda acc, x: acc x, data, 0)從底層邏輯上看二者沒(méi)有區(qū)別都是“初始值 遍歷 累計(jì)規(guī)則”。reduce的價(jià)值在于把“如何遍歷”這個(gè)細(xì)節(jié)抽象掉。讓累計(jì)邏輯可以復(fù)用、可以傳遞。減少臨時(shí)變量讓代碼更聲明式。但也要注意reduce并不是“性能銀彈”。在 Python 這類解釋型語(yǔ)言中純 Python 的reduce疊加 Lambda性能往往不如普通for循環(huán)。它的優(yōu)勢(shì)在代碼表達(dá)力和邏輯抽象層面。2.3 手動(dòng)實(shí)現(xiàn)一個(gè) Reduce看清底層邏輯為了理解reduce的底層邏輯我們來(lái)手動(dòng)實(shí)現(xiàn)一個(gè)簡(jiǎn)化版def my_reduce(func, iterable, initializerNone): it iter(iterable) if initializer is None: try: acc next(it) except StopIteration: raise TypeError(my_reduce() of empty iterable with no initial value) else: acc initializer for x in it: acc func(acc, x) return acc測(cè)試一下print(my_reduce(lambda acc, x: acc x, [1, 2, 3, 4, 5], 0)) # 15 print(my_reduce(lambda acc, x: acc * x, [1, 2, 3, 4], 1)) # 24這個(gè)自定義實(shí)現(xiàn)說(shuō)明了三件事reduce內(nèi)部就是一次循環(huán)。每次循環(huán)都執(zhí)行回調(diào)函數(shù)func?;卣{(diào)函數(shù)必須接收兩個(gè)參數(shù)上一個(gè)累計(jì)值和當(dāng)前元素。也就是說(shuō)只要你能寫出一個(gè)循環(huán)就能理解reduce反過(guò)來(lái)能看懂reduce也能手動(dòng)改寫成循環(huán)。理解這一層后面的“Reduce vs 遞歸”就有基礎(chǔ)了。3. Reduce 與遞歸誰(shuí)才是“盟主”3.1 相同點(diǎn)與不同點(diǎn)很多人把reduce和遞歸搞混因?yàn)橐恍┖瘮?shù)式語(yǔ)言比如 Haskell的foldr、foldl就是基于遞歸實(shí)現(xiàn)的。但在日常開(kāi)發(fā)中兩者有清晰的邊界。維度Reduce歸約遞歸核心思想通過(guò)累計(jì)函數(shù)把序列合并為單個(gè)值通過(guò)函數(shù)自調(diào)用拆分問(wèn)題是否依賴棧通常使用迭代實(shí)現(xiàn)不占遞歸棧每層調(diào)用占用調(diào)用棧終止條件由序列長(zhǎng)度決定天然有限必須手動(dòng)定義終止條件代碼形式高階函數(shù) 回調(diào)自己調(diào)用自己適用場(chǎng)景求和、累計(jì)、拼接、聚合樹(shù)遍歷、分治、數(shù)學(xué)定義所以“誰(shuí)是盟主”這個(gè)問(wèn)題本身沒(méi)有標(biāo)準(zhǔn)答案。二者不是競(jìng)爭(zhēng)關(guān)系而是不同層級(jí)的工具reduce是“迭代式歸約”的抽象。遞歸是“分治式拆分”的抽象。二者可以互相模擬但底層邏輯不同。3.2 用遞歸實(shí)現(xiàn) Reduce既然遞歸可以模擬幾乎所有循環(huán)當(dāng)然也能模擬reduce。def recursive_reduce(func, data, accNone): if len(data) 0: return acc if acc is None: return recursive_reduce(func, data[1:], data[0]) return recursive_reduce(func, data[1:], func(acc, data[0]))測(cè)試nums [1, 2, 3, 4, 5] print(recursive_reduce(lambda acc, x: acc x, nums, 0)) # 15這個(gè)實(shí)現(xiàn)很“函數(shù)式”但有一個(gè)致命問(wèn)題Python 默認(rèn)遞歸深度約 1000 層。如果列表很長(zhǎng)就會(huì)報(bào)RecursionError: maximum recursion depth exceeded因此在 Python 中我們不建議用遞歸實(shí)現(xiàn) reduce這只是用來(lái)理解二者關(guān)系的教學(xué)示例。3.3 用 Reduce 模擬遞歸Y 組合子思路反過(guò)來(lái)理論上也可以用reduce模擬遞歸。核心思路是把“下一次調(diào)用”作為參數(shù)傳遞下去類似Y 組合子。比如我們要用reduce計(jì)算階乘from functools import reduce def factorial_by_reduce(n): return reduce(lambda acc, _: acc * (n - (_ - 1)), range(n), 1) print(factorial_by_reduce(5)) # 120這段代碼通過(guò)range(n)模擬遞歸的“調(diào)用次數(shù)”每次用 Lambda 更新累計(jì)值。嚴(yán)格來(lái)說(shuō)這不是遞歸而是把遞歸過(guò)程“拍平”成了一個(gè)循環(huán)歸約。這種轉(zhuǎn)換在函數(shù)式編程中很有意義很多語(yǔ)言和框架會(huì)把尾遞歸優(yōu)化成迭代從而避免棧溢出。但在 Python 中官方?jīng)]有尾遞歸優(yōu)化所以更常見(jiàn)的做法是直接用循環(huán)或reduce來(lái)替代深層遞歸。3.4 循環(huán)深度與調(diào)用棧不管是循環(huán)、reduce還是遞歸最終都繞不開(kāi)“深度”這個(gè)詞循環(huán)深度由迭代次數(shù)決定通??煽?。調(diào)用棧深度由遞歸層數(shù)決定存在上限。歸約鏈深度在reduce中累計(jì)值的依賴鏈長(zhǎng)度等于序列長(zhǎng)度但內(nèi)存消耗遠(yuǎn)小于遞歸棧??匆粋€(gè)對(duì)比# 普通循環(huán)10萬(wàn)次沒(méi)問(wèn)題 s 0 for i in range(100000): s i print(s) # 遞歸10萬(wàn)層必然報(bào)錯(cuò) def sum_recursive(n): if n 0: return 0 return n sum_recursive(n - 1) # print(sum_recursive(100000)) # RecursionError # reduce10萬(wàn)元素也沒(méi)問(wèn)題因?yàn)槭堑鷮?shí)現(xiàn) from functools import reduce print(reduce(lambda acc, x: acc x, range(100000), 0))這里可以得出一個(gè)工程結(jié)論如果遞歸深度可能很大優(yōu)先考慮改寫成循環(huán)或reduce。如果業(yè)務(wù)邏輯天然是樹(shù)形結(jié)構(gòu)遞歸更清晰但要控制深度或改用顯式棧。4. 在 Excel/WPS 中的實(shí)戰(zhàn)LAMBDA REDUCE4.1 Excel 365 / WPS 中的 LAMBDA 與 REDUCE 簡(jiǎn)介近幾年的 Excel 365 和 WPS 表格逐漸加入了動(dòng)態(tài)數(shù)組函數(shù)和 LAMBDA 編程能力。其中最關(guān)鍵的兩個(gè)函數(shù)LAMBDA允許用戶自定義匿名函數(shù)并可以遞歸調(diào)用自身。REDUCE對(duì)數(shù)組中的每個(gè)元素應(yīng)用 LAMBDA 函數(shù)并返回累計(jì)結(jié)果。注意不同版本對(duì)這兩個(gè)函數(shù)的支持程度有差異。Excel 365 支持最完整WPS 較新版本也在支持中但如果你用的是 Excel 2016 或舊版 WPS可能無(wú)法使用。建議先在自己表格里測(cè)試LAMBDA(x, x * 2)(5)如果返回 10說(shuō)明你的環(huán)境支持 LAMBDA。REDUCE的語(yǔ)法是REDUCE([初始值], 數(shù)組, LAMBDA(累計(jì)值, 當(dāng)前值, 計(jì)算邏輯))這個(gè)結(jié)構(gòu)幾乎就是 Pythonreduce的表格版。4.2 示例1用 REDUCE 實(shí)現(xiàn)累計(jì)求和假設(shè) A1:A5 中有 5 個(gè)數(shù)字例如 10、20、30、40、50。在 B1 單元格輸入REDUCE(0, A1:A5, LAMBDA(acc, x, acc x))結(jié)果為 150。這個(gè)公式很容易理解acc初始為 0。用x遍歷 A1:A5。每次返回acc x。如果不想先寫初始值也可以直接把第一個(gè)元素作為初始值這樣更貼近部分語(yǔ)言中reduce的默認(rèn)行為REDUCE(A1, A2:A5, LAMBDA(acc, x, acc x))但這樣要求 A1 不為空并且數(shù)組至少有一個(gè)元素否則會(huì)返回錯(cuò)誤。實(shí)際使用時(shí)我更推薦顯式寫初始值0或邏輯更清晰。4.3 示例2用遞歸 LAMBDA 將整數(shù) n 轉(zhuǎn)換成字符串下面來(lái)一個(gè)更有代表性的例子遞歸法將一個(gè)整數(shù) n 轉(zhuǎn)換成字符串。在 Excel/WPS 中LAMBDA可以遞歸調(diào)用自身但需要先給函數(shù)起個(gè)名字。具體方法是使用“定義名稱”功能。操作步驟點(diǎn)擊“公式”選項(xiàng)卡 → “定義名稱”。名稱輸入INT_TO_STR引用位置輸入LAMBDA(n, IF(n 10, TEXT(n, 0), INT_TO_STR(INT(n / 10)) TEXT(MOD(n, 10), 0) ) )然后在任意單元格輸入INT_TO_STR(12345)返回文本字符串12345。這個(gè)公式的遞歸邏輯是終止條件n 10時(shí)直接返回單數(shù)字文本。遞歸步驟取INT(n / 10)得到去掉最后一位的整數(shù)遞歸轉(zhuǎn)換成字符串。再把最后一位MOD(n, 10)追加到后面。用示例展開(kāi)INT_TO_STR(12345) INT_TO_STR(1234) 5 INT_TO_STR(123) 4 5 INT_TO_STR(12) 3 4 5 INT_TO_STR(1) 2 3 4 5 1 2 3 4 5 12345這里需要注意WPS 和 Excel 的“定義名稱”使用絕對(duì)引用方式遞歸調(diào)用名必須和定義名稱完全一致。如果名稱定義為INT_TO_STR但在公式里寫成了INT2STR就會(huì)返回#NAME?錯(cuò)誤。4.4 示例3用 REDUCE 替代 VBA 循環(huán)批量處理在紅傳統(tǒng) VBA 宏時(shí)代對(duì)單元格循環(huán)累加經(jīng)常需要寫好幾行代碼。比如把 A 列數(shù)字累加到 B 列Sub SumLoop() Dim i As Long Dim total As Long total 0 For i 1 To 5 total total Cells(i, 1).Value Next i MsgBox total End Sub如果使用新版 WPS/Excel 的REDUCE一個(gè)單元格公式就能完成REDUCE(0, A1:A5, LAMBDA(acc, x, acc x))如果是 WPS 支持 JS 宏的版本也可以用 JavaScript 的reduce來(lái)處理表格數(shù)組數(shù)據(jù)。假設(shè)你已經(jīng)把某個(gè)區(qū)域的數(shù)值讀取到數(shù)組data中function SumRange() { let data [10, 20, 30, 40, 50]; let total data.reduce((acc, x) acc x, 0); return total; }這與 Python 中reduce的思維方式完全一致。所以掌握函數(shù)式歸約思想后你可以在不同語(yǔ)言和表格工具之間無(wú)縫遷移。4.5 用 LAMBDA REDUCE 做文本拼接除了數(shù)字求和REDUCE最常見(jiàn)的場(chǎng)景是文本拼接。比如 A1:A3 分別是A、B、C希望得到A-B-CREDUCE(, A1:A3, LAMBDA(acc, x, IF(acc , x, acc - x)))結(jié)果A-B-C這里的關(guān)鍵是處理第一個(gè)元素拼接時(shí)不要出現(xiàn)-A這種多余分隔符。邏輯是初始acc 。第一次循環(huán)acc為空直接返回x結(jié)果為A。第二次循環(huán)acc為A返回A-B。第三次循環(huán)返回A-B-C。這種寫法比 VBA 循環(huán)拼接要簡(jiǎn)潔得多而且因?yàn)槭莿?dòng)態(tài)數(shù)組函數(shù)源數(shù)據(jù)變化后結(jié)果會(huì)自動(dòng)更新。5. 常見(jiàn)問(wèn)題與排查思路問(wèn)題現(xiàn)象常見(jiàn)原因解決思路Python 報(bào)RecursionError遞歸深度超過(guò)解釋器限制改用循環(huán)、迭代或reduce或sys.setrecursionlimit臨時(shí)調(diào)大不推薦作為常規(guī)方案reduce結(jié)果不對(duì)初始值設(shè)置錯(cuò)誤檢查初始值是否符合邏輯累乘時(shí)初始值用 1累加時(shí)初始值用 0空序列調(diào)用reduce報(bào)錯(cuò)沒(méi)有提供初始值為reduce提供默認(rèn)初始值或在調(diào)用前判斷序列是否為空Excel/WPS 輸入REDUCE顯示#NAME?版本不支持 REDUCE 或函數(shù)名拼寫錯(cuò)誤檢查辦公軟件版本確認(rèn)函數(shù)名正確舊版本可用 VBA / JS 宏替代定義名稱遞歸 LAMBDA 返回#NAME?遞歸名稱未正確定義或名稱沖突檢查“定義名稱”中的名稱是否與公式內(nèi)使用名稱完全一致LAMBDA參數(shù)個(gè)數(shù)不匹配調(diào)用時(shí)參數(shù)個(gè)數(shù)和定義不一致仔細(xì)核對(duì) LAMBDA 頭和調(diào)用處的參數(shù)個(gè)數(shù)WPS 打開(kāi) Excel 文件后動(dòng)態(tài)數(shù)組結(jié)果不刷新版本不支持動(dòng)態(tài)數(shù)組自動(dòng)溢出手動(dòng)觸發(fā)重算CtrlAltF9或改用老式數(shù)組公式遞歸 LAMBDA 計(jì)算量太大導(dǎo)致卡死遞歸層數(shù)過(guò)多沒(méi)有終止條件或效率低添加明確的終止條件減少遞歸深度優(yōu)先用REDUCE替代遞歸排查遞歸以外的問(wèn)題時(shí)可以按這個(gè)順序走一遍確認(rèn)環(huán)境版本支持相關(guān)函數(shù)。在最小數(shù)據(jù)集上單獨(dú)測(cè)試 Lambda 邏輯。打印中間累計(jì)值觀察每一步結(jié)果是否符合預(yù)期。檢查終止條件是否能在有限步內(nèi)到達(dá)。檢查初始值類型數(shù)字、文本、空值是否正確。6. 最佳實(shí)踐與工程建議6.1 迭代優(yōu)先遞歸其次在日常業(yè)務(wù)代碼中處理數(shù)組、列表、序列時(shí)優(yōu)先使用循環(huán)或reduce不優(yōu)先使用遞歸。原因很簡(jiǎn)單調(diào)用棧深度不可控。只有當(dāng)數(shù)據(jù)天然形成樹(shù)結(jié)構(gòu)、目錄結(jié)構(gòu)、嵌套結(jié)構(gòu)時(shí)遞歸才是自然選擇。比如遍歷文件夾、解析 JSON 嵌套對(duì)象、處理樹(shù)形菜單。6.2 Reduce 使用時(shí)要明確初始值和回調(diào)邊界無(wú)論 Python、JavaScript 還是 Excel/WPS 的 REDUCE都要注意初始值類型要和累計(jì)邏輯匹配?;卣{(diào)函數(shù)不能修改原始數(shù)組應(yīng)返回新累計(jì)值。序列為空時(shí)有初始值就能正常返回否則會(huì)報(bào)錯(cuò)。推薦封裝一層帶默認(rèn)值的通用函數(shù)。Pythonfrom functools import reduce def safe_reduce(func, data, defaultNone): if not data: return default return reduce(func, data)JavaScriptfunction safeReduce(func, arr, defaultVal) { if (arr.length 0) return defaultVal; return arr.reduce(func); }6.3 遞歸必須“三步走”設(shè)計(jì)法第一步寫終止條件。先想好最小輸入時(shí)返回什么。第二步寫遞歸調(diào)用。確保每次都在縮小問(wèn)題規(guī)模。第三步組合結(jié)果。把當(dāng)前層的結(jié)果和子問(wèn)題結(jié)果合并。任何一個(gè)遞歸函數(shù)缺少這三步中的任意一步都會(huì)出問(wèn)題。6.4 Excel/WPS 中優(yōu)先使用 REDUCE而不是遞歸 LAMBDA在 Excel/WPS 表格中遞歸 LAMBDA 的計(jì)算效率不穩(wěn)定尤其當(dāng)數(shù)據(jù)量大時(shí)可能卡頓或觸發(fā)計(jì)算循環(huán)。對(duì)于普通序列聚合REDUCE更安全。遞歸 LAMBDA 適合那些“無(wú)法用普通公式表達(dá)”的自定義函數(shù)例如基于樹(shù)結(jié)構(gòu)的數(shù)據(jù)展開(kāi)、日期逐步推算。但請(qǐng)務(wù)必設(shè)置好終止條件和遞歸上限。6.5 注意版本兼容避免函數(shù)不可用如果你要把工作簿分享給同事一定要確認(rèn)對(duì)方的 Excel/WPS 版本是否支持動(dòng)態(tài)數(shù)組函數(shù)。穩(wěn)妥做法是先在本地測(cè)試。對(duì)關(guān)鍵結(jié)果用 VBA / JS 宏提供替代方案。在文檔中注明“需使用支持 LAMBDA 的版本”。6.6 安全與數(shù)據(jù)完整性在使用遞歸或 REDUCE 處理生產(chǎn)數(shù)據(jù)時(shí)要注意不要在高頻事務(wù)系統(tǒng)中使用深度遞歸處理大量數(shù)據(jù)避免在線程池中被阻塞。如果使用 VBA 宏或 WPS JS 宏操作單元格應(yīng)先備份工作表。對(duì)涉及刪除、覆蓋、批量修改數(shù)據(jù)的宏應(yīng)添加二次確認(rèn)。6.7 可讀性 炫技reduce和遞歸雖然很酷但并不意味著所有場(chǎng)景都適合。團(tuán)隊(duì)協(xié)作時(shí)代碼可讀性更重要。如果一個(gè)reduce聚合邏輯超過(guò)三層嵌套 Lambda建議改回普通循環(huán)并加注釋。代碼是寫給人看的順便讓機(jī)器執(zhí)行。7. 總結(jié)與學(xué)習(xí)路線這次深入討論之后你會(huì)發(fā)現(xiàn)“Reduce 和 Lambda 遞歸誰(shuí)是盟主”的問(wèn)題其實(shí)等價(jià)于“錘子和螺絲刀誰(shuí)更厲害”。工具沒(méi)有絕對(duì)優(yōu)劣只有場(chǎng)景適配。本文重點(diǎn)內(nèi)容回顧Lambda 是匿名函數(shù)是函數(shù)式編程的基礎(chǔ)磚塊。遞歸是自調(diào)用式的分治模型必須嚴(yán)謹(jǐn)設(shè)計(jì)終止條件。Reduce 是迭代式歸約封裝天然適合序列聚合。遞歸深度受調(diào)用棧限制Reduce 通?;诘鷮?shí)現(xiàn)能承載更大數(shù)據(jù)規(guī)模。在 Excel/WPS 中LAMBDAREDUCE可以把很多 VBA 循環(huán)改寫成一個(gè)公式。生產(chǎn)環(huán)境中優(yōu)先迭代慎用遞歸優(yōu)先可讀避免炫技。接下來(lái)可以按這個(gè)路線繼續(xù)深化學(xué)習(xí) Python 的itertools與functools模塊掌握accumulate、groupby、partial等。學(xué)習(xí)函數(shù)式編程中的map、filter、reduce三件套理解數(shù)據(jù)流轉(zhuǎn)換。學(xué)習(xí)尾遞歸、顯式棧模擬遞歸、動(dòng)態(tài)規(guī)劃理解遞歸到迭代的轉(zhuǎn)化。在 Excel/WPS 中多練MAP、SCAN、BYROW、BYCOL等函數(shù)構(gòu)建表格函數(shù)式思維。最后給一個(gè)實(shí)操建議從今天起遇到寫for循環(huán)累加數(shù)據(jù)時(shí)先停下來(lái)想一想這里能不能用reduce如果改用遞歸終止條件是否清晰循環(huán)深度如果變成 1 萬(wàn)、10 萬(wàn)我的代碼還扛得住嗎想清楚這三個(gè)問(wèn)題你的編程功底會(huì)再上一個(gè)臺(tái)階。如果這篇文章對(duì)你有幫助可以收藏備用也歡迎在評(píng)論區(qū)聊聊你在 WPS 表格里用 LAMBDA 踩過(guò)哪些坑。