2016年9月14日 星期三

Google Sheets: Array Lesson 4: 陣列-擴展 (Array-Expansion)

Google試算表(Sheets)函式ARRAYFORMULA()的效果,除了強迫函式參數維持多值之外,還同時附帶有另一個效果:陣列擴展(Array-Expansion)。

陣列擴展機制的目的,是為了處理「如何讓兩個不同維度的陣列一起運算?」這樣的問題。例如:兩個陣列的寬度不同,相加起來會是?兩個陣列的高度不同,相加起來會是?兩個陣列的寬度高度都不同,相加起來又會是?

陣列擴展機制定義了讓兩個陣列變成相同維度(一樣寬、一樣高)的規則。

1. 陣列擴展的必要條件


陣列擴展要能夠進行,有一些先決條件。

1.1 條件一:單值參數

  • 陣列擴展似乎只會發生在函式的單值參數上。
    • 例如:ADD()的兩個參數。
    • 也就是有被設定單值旗標(Keep-single)的參數上。
  • 不會發生在原本就接收整個陣列的參數上。
    • 例如:SUM()的所有參數。
    • 這可能是因為,這種多值參數,通常有它自己既定的運算規則,所以無法再套用陣列擴展規則。

1.2 條件二:維持多值

陣列擴展既然只發生在函式的單值參數上,但是單值參數(Keep-single)顧名思義,就是只會取用陣列中的單一值,這樣要如何擴展成相同維度的陣列呢?

所以,要讓陣列擴展發揮效果,必須先壓制單值旗標,切換到維持多值(Keep-array)的狀態。

通常,這就表示要使用ARRAYFORMULA(),把想要產生陣列擴展效果的運算式含括在其中。例如:ADD(),必須變成ARRAYFORMULA(ADD())。

有些函式也同時具有壓制單值旗標的效果,例如:FILTER()。在這種函式中,就可以不必再使用ARRAYFORMULA()。例如:ARRAYFORMULA(FILTER(ADD())),只需要直接寫FILTER(ADD())就可以了。

註:別忘了壓制單值旗標的效果往往可以遞迴,所以通常只需要在最外層使用一次ARRAYFORMULA()即可。例如:ARRAYFORMULA(ADD(ARRAYFORMULA(ADD())))其實是不必要的,ARRAYFORMULA(ADD(ADD()))就可以達成相同效果。

1.3 條件三:相關參數

有些函式的參數彼此之間,原本就不會一起進行運算,自然也就沒有讓它們變成相同維度陣列的需要。例如:IF(...,2nd,3rd)的第二與第三個參數、CHOOSE(...,2nd,3rd)的第二與第三個參數。

這時候,即使這些參數都是單值參數、而且也用ARRAYFORMULA()將該函式括起來,頂多也只會達成維持多值(Keep-array)的效果而已,並不會發生陣列擴展。

另外有些函式的單值參數,例如:CHOOSE(1st,...)的第一個參數、INDEX(...,2nd,3rd)的第二與第三個參數,即使用ARRAYFORMULA()將該函式括起來,例如:ARRAYFORMULA(INDEX(...,2nd,3rd)),卻連維持多值的效果都沒有,仍然使用維持單值(Keep-single for cell range, Keep-single for returned array)的效果。


2. 陣列擴展規則

一旦確定函式的幾個相關參數(例如:ARRAYFORMULA(ADD(1st,2nd)))之間,符合陣列擴展的條件,那麼這些參數(此時這些參數都是陣列,只是尺寸可能並不相同)就會按照下列規則,先擴展成相同尺寸的陣列:
  • 決定(最終運算結果的)陣列尺寸:
    • 找出最寬的陣列有幾欄。
    • 找出最高的陣列有幾列。
  • 擴展每陣列的尺寸:
    • 單欄的陣列,就重複這麼多欄。
    • 單列的陣列,就重複這麼多列。
    • 單值的陣列,就重複這麼多欄、也重複這麼多列。
    • 二維的陣列,則維持不變。
  • 補值
    • 經過上述擴展後,陣列的尺寸仍然有可能小於「最終運算結果」的陣列尺寸。
      • 這是因為,單欄陣列可能原本就不夠高(而擴展規則中卻只處理寬度)、單列陣列可能原本就不夠寬(而擴展規則中卻只處理高度)、二維陣列更可能原本就不夠高也不夠寬(而擴展規則中卻只是讓它維持不變)。
    • 這些空缺的陣列元素位置,全部視為具有#N/A這個值。
這麼一來,函式每個相關參數,都擴展成相同尺寸的陣列,也就可以一起進行運算。










3. 陣列公式

在試算表軟體中,通常把這種「擴展成相同維度陣列,並且進行運算」的模式,稱為「陣列公式(array formula)」。這可能是函式ARRAYFORMULA()名稱的由來。

換句話說,透過這個函式,可以讓陣列從「交集模式(Intersection)」,轉變成「重複(疊代)模式(Iteration)」。

交集模式(尤其是Keep-single for cell range)的好處,是在把公式複製到多個儲存格時,不需要手動調整每個複製後的公式,就可以讓這些公式自動採用來自不同儲存格的內容。這種效果也可以用不同方式達成,也就是在公式中使用儲存格相對定址(例如:B1,而不是絕對定址$B$1),讓公式複製到其他儲存格後,不需要調整公式內容(應該說,系統會自動幫調整複製後的相對定址)。

重複(疊代)模式的好處,是可以只在一個儲存格中輸入公式,就可以產生類似「把公式複製到多個儲存格中」的效果。可惜缺點是,只能達到「類似」的效果而已,有許多狀況(例如:循環參考、或是前面提到有些函式不受陣列擴展規則影響),還是只能透過複製公式來達成。


相關文章

1. Google Sheets: Array Lesson 1: 建立陣列 (Creating an array)
2. Google Sheets: Array Lesson 2: 陣列-交集-單值 (Array-Intersection-Single value)
3. Google Sheets: Array Lesson 3: 陣列-維持-多值 (Array-Keep-Multiple value)
4. Google Sheets: Array Lesson 5: 串接二維陣列的單個維度 (Concatenate 1D of 2D array by QUERY())

參考資料

1. Open Formula: Non-Scalar Evaluation (aka 'Array expressions')
2. Apache OpenOffice: Documentation/How Tos/Using Arrays
3. LibreOffice: Calc: Array Functions