esProc 利用剪貼簿強化 Excel 計算

cainiao_M發表於2020-12-03

遇到Excel難以實現的複雜或特殊運算時,可先用剪貼簿將資料複製到esProc,利用esProc強大的計算能力完成,再用剪貼簿返回Excel。剪貼簿方式比傳統的add-ins方式部署更簡單,操作更順滑,開發時不影響剪貼簿正常使用,且支援多個源片區和結果片區。

esProc提供了函式clipboard,可實現剪貼簿的基本用法。下面用“各科前3名的學生”為例進行說明。

Excel中處理前的資料如下,其中A列是學生姓名,B-D列分別是數學、英語、物理成績。

| | A | B | C | D |
| 1 | name | math | english | physics |
| 2 | lily | 97 | 100 | 99 |
| 3 | Joshua | 100 | 99 | 100 |
| 4 | Sarah | 98 | 99 | 96 |
| 5 | Bertram | 94 | 95 | 85 |
| 6 | Paula | 91 | 88 | 91 |
| 7 | Sophia | 92 | 81 | 76 |
| 8 | Ben | 87 | 80 | 76 |
| 9 | Ruth | 92 | 91 | 87 |
| 10 | Pag | 95 | 87 | 87 |

計算目標:求出每學科成績前3名的學生,並追加到本科目成績之後。

這個計算目標需要用到記錄集合TopN、按序號拼接等功能,Excel本身不好實現,但藉助esProc就容易多了。先在Excel中選中源片區(A1:D10),按下ctrl+C,複製到系統剪貼簿,開啟集算器IDE,編寫並執行如下指令碼:

| | A | B |
| 1 | =clipboard().import@t() | /從剪下板讀取資料 |
| 2 | =A1.top(-3;math).(name) | /math前3名 |
| 3 | =A1.top(-3;english).(name) | |
| 4 | =A1.top(-3;physics).(name) | |
| 5 | =join@p(A2;A3;A4).export() | /拼成二維表,轉成字串 |
| 6 | =clipboard(A5) | | /向剪下板寫資料 |
| | | | |

上面程式碼中,clipboard函式有兩種形態,其中無引數呼叫該函式時,可返回剪貼中的字串,如A1格;以變數或格名為引數呼叫該函式時,可向剪貼簿寫入字串,形如A6中的clipboard(var)。

執行上述指令碼後,在Excel的B11格用ctrl+V,即可將剪下板中的資料複製到B11-D13,如下:

| | A | B | C | D |
| | … | … | … | … |
| 10 | Pag | 95 | 87 | 87 |
| 11 | | Joshua | Lily | Joshua |
| 12 | | Sarah | Sarah | Lily |
| 13 | | lily | Joshua | Sarah |

但是,我們在編輯除錯指令碼時,保不齊會用一下複製貼上,這時候就把剪貼簿的內容沖掉了,再執行clipboard()時, 返回的內容就是剛才編輯的程式碼,這樣就無法完成計算了,只能再回到Excel去重新複製,有點麻煩。

針對這個問題,esProc提供了clipboard@e()函式,選項@e表示始終返回第一次從Excel複製到剪貼簿中的資料。下面讓我們試一下。

在“各科前3名的學生”這個例子中,假設我們已經從Excel複製了資料,並寫完了指令碼。此時編輯指令碼,將A3、A4移動到B2、B3,再執行指令碼時,就會因為A1中的clipbaord()取到錯誤資料,而導致A2報錯。現在修改程式碼,在A1使用剛才提到的clipboard@e(),則移動程式碼後可正確執行。編輯後的程式碼如下:

| | A | B | C |
| 1 | =clipboard@e().import@t() | /從剪下板讀取資料 | |
| 2 | =A1.top(-3;math).(name) | =A1.top(-3;english).(name) | =A1.top(-3;physics).(name) |
| 3 | =join@p(A2;B2;B3).export() | /拼成二維表,轉成字串 | |
| 4 | =clipboard(A3) | /向剪下板寫資料 | |

clipboard(…)只能返回一個結果,但有些較複雜的運算可能需要返回多個結果,這該怎麼辦呢?

其實 ,在esProc的結果顯示區可以直接把多個格值(或變數值)分別複製到剪貼簿,並依次返回Excel。

下面用 “各科前3名和每個人的超越目標”為例進行說明。

計算目標:在學生成績單的基礎上,不僅在各科目下面追加本科目前3名的學生,而且需要新加一列target,計算出比本人總分略高的3名學生的名單列表,作為本人應當超越的目標。注意,有些人的超越目標不足3人,每個超越目標之間須用>號連線。

先在Excel中選中源片區(A1:D10),按下ctrl+C,複製到系統剪貼簿,開啟esProc IDE,編寫並執行如下指令碼:

| | A | B | C |
| 1 | =clipboard@e().import@t() | 從剪下板獲取資料 | |
| 2 | =A1.top(-3;math).(name) | =A1.top(-3;english).(name) | =A1.top(-3;physics).(name) |
| 3 | =join@p(A2;B2;C2) | 片區1:各科前3名 | |
| 4 | =A1.derive(sum(math,english,physics):subtotal) | 每個人的總分 | |
| 5 | =A4.derive(t=subtotal,A4.select(subtotal>t):beforeMe) | 排在本人前面的學生 | |
| 6 | =A5.new(beforeMe.top(3;subtotal).(name).concat(“>”):target) | 片區2:最近3名學生 | |

上述程式碼中,A3儲存結果片區1,即本科目前3名的學生;A4儲存結果片區2,即每個人的超越目標。另外應當注意到,程式碼中無須export()和clipboard(…)。

下面將計算結果返回Excel。先點選片區1,再點選右側對應的“copy data”按鈕,如下圖:

imagepng

在Excel 的B11 格用ctrl+V ,即可將片區1 複製到B11-D13 ,如下:

| | A | B | C | D |
| 1 | name | math | english | physics |
| 2 | Lily | 97 | 100 | 99 |
| 3 | Joshua | 100 | 99 | 100 |
| 4 | Sarah | 98 | 99 | 96 |
| 5 | Bertram | 94 | 95 | 85 |
| 6 | Paula | 91 | 88 | 91 |
| 7 | Sophia | 92 | 81 | 76 |
| 8 | Ben | 87 | 80 | 76 |
| 9 | Ruth | 92 | 91 | 87 |
| 10 | Pag | 95 | 87 | 87 |
| 11 | | Joshua | lily | Joshua |
| 12 | | Sarah | Sarah | lily |
| 13 | | lily | Joshua | Sarah |

再點選指令碼中的片區2,按住shift的同時,點選右側對應的“copy data”按鈕,之後在Excel的的E1格按下ctrl+V,即可將片區2連帶列名複製到E1:E10。如下所示:

| | A | B | C | D | E |
| 1 | name | math | english | physics | Target |
| 2 | Lily | 97 | 100 | 99 | Joshua |
| 3 | Joshua | 100 | 99 | 100 | |
| 4 | Sarah | 98 | 99 | 96 | lily>Joshua |
| 5 | Bertram | 94 | 95 | 85 | Sarah>lily>Joshua |
| 6 | Paula | 91 | 88 | 91 | Bertram>Sarah>lily |
| 7 | Sophia | 92 | 81 | 76 | Pag>Ruth>Paula |
| 8 | Ben | 87 | 80 | 76 | Sophia>Pag>Ruth |
| 9 | Ruth | 92 | 91 | 87 | Bertram>Sarah>lily |
| 10 | Pag | 95 | 87 | 87 | Ruth>Paula>Bertram |
| 11 | | Joshua | lily | Joshua | |
| 12 | | Sarah | Sarah | lily | |
| 13 | | lily | Joshua | Sarah | |

在上述操作中,我們可通過shift控制計算結果是否帶列名,這是esProc的獨有方式,其他計算工具不具備此項功能。

解決了多目標的問題後,我們很容易聯想到有多個源的問題。計算可能需要使用Excel的多個源片區,但clipboard只能保持最新複製的那一片,這又該怎麼辦?

有辦法,可以把剪貼簿內容直接複雜到格子裡面去。

下面用 “查詢符合指定條件的訂單”為例進行說明。

Excel中有兩個sheet,訂單明細和員工名單,其中訂單明細如下:

| | A | B | C | D | E |
| 1 | OrderID | Client | SellerId | Amount | OrderDate |
| 2 | 1 | WVF Vip | 1 | 440 | 2014-11-03 |
| 3 | 2 | UFS Com | 1 | 1863 | 2015-01-01 |
| 4 | 3 | SWFR | 2 | 1813 | 2014-11-01 |
| 5 | 4 | JFS Pep | 2 | 671 | 2015-01-01 |
| 6 | 5 | DSG | 1 | 3730 | 2015-01-01 |
| 7 | 6 | JFE | 1 | 1445 | 2015-01-01 |
| 8 | 7 | OLF | 3 | 625 | 2015-01-01 |
| 9 | 8 | PAER | 3 | 2490 | 2015-01-01 |

員工名單如下:

| | A | B | C | D | E | F | G |
| 1 | EId | State | Dept | Name | Gender | Salary | Birthday |
| 2 | 2 | New York | Marketing | Ashley | F | 11001 | 1980-07-19 |
| 3 | 3 | New Mexico | Sales | Rachel | F | 9000 | 1970-12-17 |
| 4 | 4 | Texas | HR | Emily | F | 7000 | 1985-03-07 |
| 5 | 5 | Texas | R&D | Ashley | F | 16000 | 1975-05-13 |
| 6 | 6 | California | Sales | Matthew | M | 11000 | 1984-07-07 |
| 7 | 7 | Illinois | Sales | Alexis | F | 9000 | 1972-08-16 |
| 8 | 8 | California | Marketing | Megan | F | 11000 | 1979-04-19 |
| 9 | 1 | Texas | HR | Victoria | F | 3000 | 1983-12-07 |

計算目標:查詢出最近days天內或訂單屬於部門列表depts的資料,需要的列有訂單編號、日期、金額、銷售員名字、部門名稱。其中days是外部引數,每次執行時都可以輸入不同的值,比如輸入30表示查詢30天內的訂單;depts也是外部引數,比如[“Markeding”,”Finance”]。這個計算目標涉及動態查詢和多鍵值查詢,Excel本身不好實現,但藉助esProc就容易多了。

首先,在Excel中選定片區“訂單明細”,連帶列名一起復制貼上到esProc指令碼的A1單元格;同樣地,將片區“員工名單”複製到esProc指令碼的A1單元格。如下圖:

imagepng

注意,一定要進入A1格的編輯狀態才能進行復制,不然會把剪貼簿的內容填進一大片格子,結果可能變成這樣:

imagepng

這就不好了,佔有區域太大,會影響程式碼佈局。

如果操作正確,A1/A2格外觀上只呈現很小一部分資料,點選後才會呈現完整資料,這是網格式程式碼的獨特之處,適合在不影響閱讀和程式碼佈局的情況下複製大片資料。

複製完兩個源片區後,繼續編寫指令碼,期間可多次執行指令碼,可手工操作剪貼簿。最後程式碼如下:

| | A | B | C |
| 1 | OrderID Client… | =A1.import@t() | /order list |
| 2 | EId State… | =A2.import@t() | /employee list |
| 3 | =B1.switch(SellerId,B2:EId) | | /Join with EId |
| 4 | =A3.select(OrderDate>=after(date(now()),days*-1)|| depts.pos(SellerId.Dept)) | | /Search data |
| 5 | =A4.new(OrderID,OrderDate,Amount,SellerId.Name:Name,SellerId.Dept:Dept) | | /return fields needed |

完成計算後,可用“copy data”按鈕將A5中的計算結果拷貝回Excel。有一點需要注意,儲存程式碼時應當把A1/A2格的資料清除掉,否則這些大片資料也會被一起儲存起來了。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章