Excel的數據處理方式來到了一個十字路口,是繼續沿用的方式還是使用函數式編程的思路。後者可以很方便的創建業務邏輯和數據分離的解決方案,其優勢是非常明顯的。
今天我們簡單介紹一下Excel中的函數式編程。
在Excel中提到編程,很多人的第一反應是VBA,宏等詞彙,下一步的反應就是:
那東西太難了!
我肯定學不會!
其實,我們這裡說的是“函數式”編程。它沒有那麼複雜,也沒有那麼高的學習難度,因為它全部是使用Excel的函數創建公式而已。
你需要做的是調整在Excel中使用函數處理數據的思路。
函數式編程,Functional Programming,跟面向對象編程一樣,是一種編程範式。
它的主要特點就是将一切都看作函數。
這恰恰是Excel所擅長的。
尤其是Excel現在已經支持了動态數組,有了LET,LAMBDA等高級函數,已經成為了一個“圖靈完備”的編程平台了。
當然,我們絕不是要成為傳說中的“程序員”,我們不需要學習過多的編程理論知識,我們隻不過是要處理數據而已。
不過是在處理數據時稍微改變一下思路而已。
沒錯,隻要你使用了Excel,你就已經在編程了。
不信,你往下看。
這是一個司空見慣的簡單表格:
A2:D2中有數據;A4:A6中有公式計算。從具體公式來看,A4和A5單元格是輔助單元格,用于保存中間結果的,A6單元格才是我們需要的結果。
現在,忘掉表格,将其中有數據或公式的單元格記錄下來,比如記錄在一個文本文件中:
象不象一個簡單的程序!
其實還可以更象一點,在Excel中你甚至可以使用變量:名稱。
比如,我們将A2:D2單元格分别命名為x,y,n,m,将A4,A5分别命名為step1,step2,
公式就變成這樣了:
再一次,将表格去掉,隻記錄數據和公式的單元格:
任何一個程序員都不會懷疑這是一段貨真價實的程序。
但是這種“程序”是有很大的缺陷的:
可讀性差 - 相信大家都有個讀不懂别人寫的公式的經曆。甚至連自己以前寫的公式都不一定讀的懂。
可移植性差 -因為你的公式實際上是跟表格緊密綁定的。比如,在上面的例子中,要将A6中的公式用到其他表格,不僅僅目标表格中A2:D4需要有數據,還必須同時将A4,A5一起一緻過去。
其中,業務邏輯和數據緊密綁定是這種方案的最大問題。修改數據結構時需要同時修改公式(即業務邏輯),其中,輔助單元格,輔助列,輔助表等中間數據加劇了這個問題。
Excel中的LET公式邁出了非常重要的一步,讓我們通過一個公式就得到最後的計算結果,擺脫了對這些中間結果的依賴:
可以看到,整個公式中不過是複制了之前定義名稱之後的一系列公式而已。但是表格清爽多了:
進一步,還可以将業務邏輯和數據完全分離,将業務邏輯封裝在一個自定義函數中:
之後就可以對所有形式的數據應用同樣的業務邏輯了:
=rslt(A3,B3,C3,D3)
=rslt(x,y,n,m)
=rslt(1,2,3,4)
這就是我們使用函數式編程處理數據的追求:
業務邏輯和數據分離!
下面我們看一個實際例子:
表格中記錄了每個員工的能力評估,包括通用能力和領導力,現在我們需要根據這兩個能力為員工評級,評級規則如下:
每個能力高低的評價依據是看看該項得分是否大于全體員工該項得分的中間值(即最大值和最小值的平均值)。
你可以先想一下自己會如何寫這個公式。
多數情況下,你會寫出一個這樣的公式:
=IF(AND(D2>(MIN(D2:D55)+MAX(D2:D55))/2,E2>(MIN(E2:E55)+MAX(E2:E55))/2), "A",IF(AND(D2>(MIN(D2:D55)+MAX(D2:D55))/2,E2<(MIN(E2:E55)+MAX(E2:E55))/2),"B",IF(AND(D2<(MIN(D2:D55)+MAX(D2:D55))/2,E2>(MIN(E2:E55)+MAX(E2:E55))/2),"C","D")))
這個公式使用嵌套的IF公式進行判斷,判斷的依據是通用能力是否超過中間值以及領導力是否超過中間值。
這個公式的缺陷我們就不重複了!無論是可讀性,可維護性,可移植性都很差。
你可能可以改進這個公式,比如将通用能力和領導力中間值的計算從公式中移出,放到單元格L1:M2中,
這裡的公式變成了:
=IF(AND(D2>($L$1+$M$1)/2,E2>($L$2+$M$2)/2), "A",IF(AND(D2>($L$1+$M$1)/2,E2<($L$2+$M$2)/2),"B",IF(AND(D2<($L$1+$M$1)/2,E2>($L$2+$M$2)/2),"C","D")))
簡化了嗎?也許,從長度上看是簡化了。
但是可讀性并沒有真正的提高。而且,公式更加緊密的與表格布局結合在了一起。要在其他表格中用同樣的邏輯進行分級,必須同時再現L1:M2的計算。
那麼,如果我們怎麼才能創建業務邏輯與數據分離的方案呢?
這個過程設置都不需要借助Excel。
首先,我們對問題進行分析,我們的要求實際上是創建一個函數:
GRADE
這個函數依賴于四個對象:
個人通用能力得分 - 記作g
全體通用能力得分 - 記作gs
個人領導力得分 - 記作l
全體領導力得分 - 記作ls
即得到一個函數:
GRADE(l, gs, l, ls)
這個函數的處理邏輯可以通過下面的公式表示:
=if(
and(通用能力.高, 領導力.高),
“A”,
if(and(通用能力.高,領導力.低),
“B”,
if(
and(通用能力.低,領導力.高),
“C”,
“D”
)
)
)
這個邏輯實際上就是之前我們在Excel中實現的公式方案。隻不過現在我們将其參數抽象為一些變量。
這個邏輯中還需要解決一個問題,即判斷通用能力和領導力的分數高低。這就需要一個中間函數:
HIGH_LOW(s, totals)
其中,
s -個人得分
totals - 全體得分
實現邏輯可以使用下面的公式:
=if(s>=(min(totals)+max(totals))/2,“高”,“低”)
有了這個HIGH_LOW函數,GRADE中的邏輯就可以實現了。
問題已經從邏輯上被解決了。剩下的事情就是在Excel中實現它們。
//判斷得分高低
HIGH_LOW = LAMBDA(
s, //個人得分
totals, //全體得分
IF(s >= (MIN(totals)+MAX(totals))/2,"高","低")
);
//根據領導力和通用能力得分在全體得分中的位置,為候選人分級
GRADE = LAMBDA(
g, //個人通用能力得分
gs, //全體通用能力分數列表
l, //個人領導力得分
ls, //全體領導力分數列表
LET(
g_hl, HIGH_LOW(g, gs), //個人通用能力高或低
l_hl, HIGH_LOW(l, ls), //個人領導力高或低
IF(
and(g_hl="高",l_hl="高"),
"A",
IF(
AND(g_hl="高",l_hl="低"),
"B",
IF(
AND(g_hl="低",l_hl="高"),
"C",
"D"
)
)
)
)
)
在高級公式環境中創建上面的兩個自定義函數。
到現在為止,我們都沒有用到數據,僅僅是在實現業務邏輯而已。
下面就可以使用自定義函數具體處理數據了:
這個公式可以導出移植,因為它不牽涉到任何的數據。即使數據布局和結果發生了改變,也不需要改變自定義函數的定義,因為業務邏輯并沒有改變。
詳細解釋請看視頻
加入E學會,學習更多Excel應用技巧
/portal/learn/class_list
Excel+Power Query+Power Pivot+Power BI
自定義函數底部菜單:知識庫->自定義函數
面授培訓底部菜單:培訓學習->面授培訓
Excel企業應用底部菜單:企業應用
也可以在曆史文章中學習Excel,Power Query,Power Pivot,Power BI,Power Automate各種技巧。
有話要說...