APL Code Golfing

APL實在是code golfing的利器。

今日突然想練一練code golf,馬上到code-golf.io看看,見到一道列印首二十行Pascal Triangle的題目,而排行第一的挑戰者居然使用了52個字元的答案。直覺告訴我APL應該可以更精煉,於是決定試試挑戰。

先公佈我的題解,只需要26個字元:



題目比預期中難,用了差不多半個小時仍然處理不好base case,即單一元素的陣列{1}。按下面來自維基的示範,當輸入為陣列V = {1, 3, 3, 1},應先將第1、2個元素相加並得出新元素1 + 3 = 4,如是者再重複相加第2、3及3、4個元素,得出新元素3 + 3 = 6與3 + 1 = 4:




(圖片鏈結自維基百科)

於是問題便轉化為產生陣列{1, 3, 3, 1}的指標的二元組(2-tuple) {1, 2},{2, 3},{3, 4}。用以存取陣列V的元素,並相加起來:




再費一些功夫抽取對角線上的元素{4, 6, 4}便可以了,感覺好像快將完成解答。

幾個想法突然湧現:
  • 這樣的程式碼只是將程序式編程(procedural programming)的思維照搬不誤
  • 程式碼極為欠缺美感,且勢必多於52個字元
  • 致命的是,當陣列V為{1}的時候,會引致錯誤

原因係當V為{1}時, ⍴(¯1↓⍳⍴V) (1↓⍳⍴V) 的外積(outer product)是空的二維陣列,導致匿名函數 {+/V[⍺ ⍵]} 發生錯誤。縱使以常理推斷,陣列中沒有任何元素的時候,前述的函數應該不會被呼叫才對。例如python之中將必然拋出錯誤的lambda用於空陣列上:



再仔細思考,輸入陣列{1, 3, 3, 1}時只需要將輸入去掉頭、尾 (即{1, 3, 3}與{3, 3, 1})相加便可得出{4, 6, 4},再無條件地將{1}置於{4, 6, 4}的頭、尾,就可以得出Pascal Triangle的第五行{1, 4, 6, 4, 1}。

直觀地翻譯為APL,就得出題解使用的匿名函數 {1,⍨1,(¯1↓⍵)+1↓⎕←⍵} ,最重要係當輸入為純量1或者陣列{1}時,輸出都會係{1, 1}。

不太理解為何其他參與者不用J語言作答,相信可以得出更精簡的答案呢。

留言

這個網誌中的熱門文章

Project Euler第八題

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