跳到主要內容跳到頁尾

LAMBDA 與 LET 基礎:自訂函式、MAP 與 REDUCE

11 分鐘閱讀Lv.5 進階摘要與日期

用 LET 幫重複出現的算式取名字,用 LAMBDA 自己定義函式並存成具名函式,再搭配 MAP 一格一格套用、用 REDUCE 一路累計成一個值,附 BYROW、BYCOL、SCAN、MAKEARRAY 的最短介紹。

發布 更新

文章目錄

如果你的算式裡有一段東西一直重複出現:,B2*C2 就寫了三次,改一個地方還得記得改另外兩個。今天來聊聊 LET 跟 LAMBDA:前者幫算式裡的值取名字,後者讓你自己定義函式,最後再接上 MAP 跟 REDUCE 兩個吃 LAMBDA 的函式。

重複的算式有多麻煩

我手上有一張手搖飲的銷售表,5 個品項,有單價跟賣出的杯數:

ABC
1品項單價杯數
2蘋果紅茶4537
3烏龍奶茶55112
4蘋果綠茶458
5青茶3564
6桂花烏龍5021

我想算每個品項的營業額,也就是單價乘上杯數,而且營業額只要達到 2000 就打 9 折。先手算第一列:45 × 37 = 1665,沒到 2000,維持 1665。第二列 55 × 112 = 6160,打 9 折是 5544。

如果直接寫成算式,放在 E2,就是:

Google 試算表公式
fx

營業額達 2000 打 9 折,B2*C2 重複了三次

=IF(B2*C2>=2000, B2*C2*0.9, B2*C2)

這條算式沒有錯,只是 B2*C2 出現了三次。折扣門檻或計算方式一改,我就得改三個地方,而且很容易只改到兩個。這時候就可以請 LET 出場。

LET

LET 讓你先替一段計算取個名字,後面的算式直接用名字。

語法

  • 名稱1、值1:第一組,名稱自己取,值可以是數字、儲存格或一段計算。
  • 名稱2、值2:選填,可以接著寫第二組、第三組。後面的值可以用前面取好的名稱。
  • 算式:最後一個參數,用前面取好的名稱算出最後要回傳的結果。

名稱和值要成雙成對地出現,最後單獨留下的那一個就是算式。這邊的名稱我通常寫簡單的英文單字,像 sales、rate。

範例

把剛剛的題目改用 LET 寫,就是:

Google 試算表公式
fx

先把營業額取名 sales、折扣取名 rate,再相乘

=LET(sales, B2*C2, rate, IF(sales>=2000, 0.9, 1), sales*rate)
  • sales, B2*C2:把單價乘杯數的結果取名叫 sales。
  • rate, IF(sales>=2000, 0.9, 1):折扣取名叫 rate,營業額達 2000 是 0.9,否則是 1。這邊直接用了前一組的 sales。
  • sales*rate:最後的算式,營業額乘折扣。

B2*C2 現在只寫了一次。把這條算式往下填到 E6,來看看結果:

E
21665
35544
4360
52016
61050

跟手算一樣:烏龍奶茶 6160 × 0.9 = 5544,青茶 2240 × 0.9 = 2016,其他沒到 2000 的維持原價。

我自己的習慣是,看到算式裡有同一段東西出現兩次以上,就先想能不能用 LET 解決。算式讀起來也比較像在讀句子:「營業額是這個、折扣是那個、兩個相乘」。

LAMBDA

LET 的名稱只活在那一條算式裡。如果同樣的計算想在很多地方重複使用,而且每次帶入不同的值,就輪到 LAMBDA:把一段計算包成一個自己定義的函式。

語法

  • 名稱1:第一個要傳進來的值,名稱自己取,但不能像儲存格參照(例如 c1),不能含空格或特殊字元(底線、點可以用),也不能以數字開頭。
  • 名稱2:選填,還有別的值要傳進來就接著寫。
  • 算式:最後一個參數,用前面取好的名稱寫出計算。

這邊跟 LET 不一樣,前面的名稱只是「預留位置」,還沒有放任何值。所以只寫 LAMBDA 本身是不會算出結果的(儲存格會顯示 #N/A,提示「LAMBDA 函式的後面必須接著含有實際值的呼叫」),要在後面再接一組括號,把真正的值傳進去。

Excel 365 也有 LAMBDA,以及 MAP、REDUCE 這一家族的函式,Excel 2021 則沒有 LAMBDA。

直接呼叫

先用最簡單的乘法試試看。我想把 B2 跟 C2 傳進去相乘:

Google 試算表公式
fx

直接在 LAMBDA 後面接括號傳值,單價 45 乘杯數 37

=LAMBDA(price, qty, price*qty)(B2, C2)
  • price, qty:兩個預留位置的名稱。
  • price*qty:用這兩個名稱寫的算式。
  • (B2, C2):真正傳進去的值,順序跟前面的名稱一一對應,所以 price 是 B2 的 45,qty 是 C2 的 37。

你應該會得到 1665,跟前面手算的一樣。

直接在 LAMBDA 後面接括號只適合拿來測試。實際在用的時候,它很少單獨出現,不是被存成具名函式,就是被當成參數交給 MAP、REDUCE 這類函式,下面兩節就是這兩種用法。

把 LET 放進 LAMBDA 裡也完全沒問題,把整段折扣邏輯包起來,傳 B3 跟 C3 進去:

Google 試算表公式
fx

LAMBDA 裡面用 LET,傳入烏龍奶茶的單價與杯數

=LAMBDA( price, qty, LET(sales, price*qty, rate, IF(sales>=2000, 0.9, 1), sales*rate) )( B3, C3 )

結果是 5544。

存成具名函式

每次都要把整條 LAMBDA 貼過去,其實也不方便。Google 試算表可以把它存成具名函式,之後像 SUM 一樣直接打名字。

  1. 點開畫面上方的「資料」>「已命名函式」,右側會出現面板。
  2. 按下「新增函式」,函式名稱填 NET_SALES。
  3. 「引數預留位置」填 price、qty,每個輸入後按 Enter,就會變成標籤。
  4. 公式定義填 ,這邊不用再寫 LAMBDA,因為引數預留位置已經在上一步定義了。
  5. 按「繼續」,確認函式預覽(可以順便填引數說明),再按「建立」。

步驟:資料 > 已命名函式,在右側面板填入函式名稱、引數預留位置與公式定義

圖:函式名稱、引數預留位置、公式定義,對應 LAMBDA 的三個部分。

存好之後,在 E2 就可以這樣用:

Google 試算表公式
fx

用具名函式算營業額,折扣規則只寫在函式定義裡

=NET_SALES(B2, C2)

結果跟前面一樣,E2 是 1665。以後折扣規則改了,只要回「已命名函式」的面板改定義那一處,所有用到 NET_SALES 的格子都會跟著變。

具名函式是跟著這份試算表走的,換一份新的試算表要用的話,需要從別份試算表匯入。這邊先帶到能用為止,「已命名函式」面板的其他設定就不展開了。

MAP

寫好一個函式之後,常會想對一整欄的每一格都跑一遍。MAP 就是做這件事:它一格一格把資料交給 LAMBDA,再把每次的結果排成一欄。

map 在中文是「對應、映射」的意思,簡單來說就是「每一個進去,每一個出來」。

語法

  • 陣列1:要處理的範圍。
  • 陣列2:選填,有第二個範圍就接著寫,大小要跟陣列1 一樣。
  • LAMBDA:最後一個參數,長得像 LAMBDA(名稱1, [名稱2, ...], 算式)。有幾個陣列,LAMBDA 裡就要有幾個名稱,依序對應。

範例

我想一個公式算出 5 個品項的營業額,不打折。單價是 B2:B6、杯數是 C2:C6,兩個範圍都要交給 MAP:

Google 試算表公式
fx

把單價與杯數兩欄一格一格配對,相乘

=MAP(B2:B6, C2:C6, LAMBDA(price, qty, price*qty))
  • B2:B6、C2:C6:兩個範圍。
  • price, qty:price 依序拿到 B 欄的每一格,qty 依序拿到 C 欄的每一格。
  • price*qty:每一組算一次。

公式只要放在 E2,結果會自己往下展開到 E6。來看看結果:

E
21665
36160
4360
52240
61050

要連折扣一起算也沒問題,把剛剛 LET 的邏輯整段放進 LAMBDA:

Google 試算表公式
fx

MAP 搭配 LAMBDA 與 LET,一個公式算出打折後的營業額

=MAP( B2:B6, C2:C6, LAMBDA( price, qty, LET(sales, price*qty, rate, IF(sales>=2000, 0.9, 1), sales*rate) ) )

這樣 E2 到 E6 是 1665、5544、360、2016、1050,跟前面逐列填算式的結果一樣,但只有一個公式。這裡的 B2:B6、C2:C6 是固定五列;新增品項後,仍須同步延伸兩個來源範圍,不能只因使用 MAP 就自動包含第 7 列。

只傳一個範圍也可以。比方說杯數 50 杯以上的品項標「熱賣」:

Google 試算表公式
fx

只傳杯數一欄,達 50 杯標熱賣,其餘標一般

=MAP(C2:C6, LAMBDA(qty, IF(qty>=50, "熱賣", "一般")))
E
2一般
3熱賣
4一般
5熱賣
6一般

簡單的運算,像這個標記熱賣的例子,用 ARRAYFORMULA 就夠了,我通常還是用 ARRAYFORMULA,比較短。當每一格要做的事需要好幾個步驟、想用 LET 取名字的時候,我才會換成 MAP。

REDUCE

MAP 是一個進去、一個出來。REDUCE 則是把一整個範圍「縮」成一個值,reduce 在中文是「縮減」的意思。

語法

  • 初始值:累計的起點。
  • 陣列:要一格一格處理的範圍。
  • LAMBDA:最後一個參數,要有兩個名稱:LAMBDA(累計, 目前, 算式)。第一個名稱拿到「到目前為止累計的值」,第二個名稱拿到「這一輪的那一格」,算式算出來的結果,會變成下一輪的累計。

範例

先從最單純的開始:把 C 欄的杯數加總。手算是 37 + 112 + 8 + 64 + 21 = 242,寫成 REDUCE:

Google 試算表公式
fx

累計從 0 開始,每一輪加上目前這一格的杯數

=REDUCE(0, C2:C6, LAMBDA(acc, qty, acc+qty))
  • 0:初始值,累計從 0 開始。
  • C2:C6:要處理的範圍。
  • acc:目前累計的值,qty:這一輪的杯數。
  • acc+qty:累計加上這一格,就是下一輪的累計。

每一輪的狀況是這樣:

輪次accqtyacc+qty
103737
237112149
31498157
415764221
522121242

最後的結果是 242。要加總的話,其實直接用 SUM(C2:C6) 就好,這邊只是拿它來看清楚 REDUCE 怎麼一輪一輪走。

那什麼時候會想用 REDUCE?當每一輪的結果要依賴上一輪的時候。比方說蘋果紅茶的單價 45,連續調價三次:先漲 10%,再降 5%,最後漲 8%。調幅放在 G2:G4,分別是 0.1、-0.05、0.08。

手算一次:45 × 1.1 = 49.5,49.5 × 0.95 = 47.025,47.025 × 1.08 = 50.787。三次調整後是 50.787。

如果用 REDUCE 寫,就是:

Google 試算表公式
fx

從 45 開始,每一輪乘上 (1 + 調幅)

=REDUCE(45, G2:G4, LAMBDA(price, change, price*(1+change)))

來看看結果:50.787,跟手算一致。這種「上一輪的輸出是下一輪的輸入」的算法,只用 SUM 或 SUMPRODUCT 這類函式比較難一次寫完,這是 REDUCE 派得上用場的地方。

其他幾個吃 LAMBDA 的函式

還有四個同一家族的函式,這邊只放最短的一個例子,語法差不多,只是 LAMBDA 拿到的東西不一樣。都用前面那張表,單價 B2:B6、杯數 C2:C6:

  • BYROW:一列一列處理。,每一列的單價乘杯數,得到 1665、6160、360、2240、1050。
  • BYCOL:一欄一欄處理。,每一欄的最大值,橫向展開成兩格,55 跟 112。
  • SCAN:跟 REDUCE 一樣一輪一輪累計,不過每一輪的結果都保留下來。,得到 37、149、157、221、242,就是上面那張輪次表裡最右邊的那一欄。
  • MAKEARRAY:不吃現成的範圍,自己指定列數與欄數,LAMBDA 拿到列號跟欄號。,產生 3 × 3 的乘法表。

MAKEARRAY 的結果長這樣:

EFG
2123
3246
4369

練習

1

加料之後的營業額

每個品項都加 5 元的珍珠,也就是單價 +5,不打折。請用一個 MAP 公式,算出 5 個品項各自「(單價 + 5)× 杯數」的結果。單價在 B2:B6,杯數在 C2:C6。

小測驗

LET、LAMBDA 與 REDUCE

0 / 3 題已完成
1

的結果是多少?

1 / 3

這篇的公式都不算長,可以先挑你手上一條重複了好幾次的算式,用 LET 改寫看看,感覺一下名稱帶來的差別。

我是喜特先生,Mr. Sheet,我們下個教學見!

分享:
喜特先生 Mr. Sheet

喜特先生 Mr. Sheet

數據分析師/商業分析師

八年工作經驗,跨不同業界解決數據需求。做過的案例都整理在作品集。

接下來可以

這篇在技能樹的 Lv.5「系統設計與最佳實踐」,模組「LAMBDA」(第 1/1 篇)。讀完這篇,路線上的下一個模組是「完整系統設計案例」。

回到技能樹

相關文章

查看所有文章

留言討論

共 0 則留言

訂閱電子報,新文章上線就通知你

免費,隨時可取消。

送出即表示同意服務條款與隱私權政策。