Let's Split!

這是2020年度的Dyalog APL的其中一道題目在,此分享一下解答過程的思考歷程。

先看看題目:

簡單解說一下:寫出函數 F,右引數 Y 可以為向量或陣列,左引數 X 為任何非零的數字,任何情況下返回一個陣列 C。當 X 為正數時,C 的第一個元素包含 Y 的首 X 個元素,C 的第二個因素為餘下之 Y 的元素;當 X 為負數時,C 的第一個元素包含 Y 的尾 X 個元素,C 的第二個因素為餘下之 Y 的元素。

好似越講越複雜,還是看看上圖的示例比較直觀,反正就係 "split" 嘛。

過往,要不使用 if-else 邏輯的情況下同時處理向量、陣列輸入會有點困難。不過題目裏面貼心地提示可以使用 ↑ (take) 函數。而 ↑ 函數正好可以"乾淨地"解決這問題。示範一下 ↑、↓ 的用法:

3 ↑ Y 意思即從 Y 中提取 (take) 頭3個元素。當左引數為負數時,將從 Y 的末端取出相應數量元素:

而另一個相反效應的函數係 ↓ (drop),果效正如其名字:

以同一個數字 X 同時 take、drop 同一個陣列,就可達到分開陣列的效果:

不過題目還要求左引數為負數時,末段的元素要放置在輸出的前方。抽象一點理解,即係有條件地反轉上面輸出的陣列的兩個元素。於是之前介紹過的 ⍣ (power) 運算子便派上用場,用於有條件地呼叫 ⊖ (rotate) 函數一次:

由於 take、drop 本身可以處理向量及陣列輸入,上面的表達式同樣可以正確分隔向量成為單一因素的陣列,以及一個空陣列(否則過不了 Dyalog 網頁的 test case):

綜合上述後的答案是: {(⊖⍣(⍺<0)) (⍺↑⍵) (⍺↓⍵)}

留言

這個網誌中的熱門文章

APL Code Golfing

Project Euler第八題

Dyalog APL比賽-2019年-Phase 1-第2題