開(kāi)篇先聽(tīng)歌。"Let's Dance to Joy Division",英國(guó)樂(lè)隊(duì)Wombat的歌。歌詞意外貼合編程博客:"我昨晚想通了一件事,改變了這個(gè)小男孩的腦子,花了22年才悟出的小建議,現(xiàn)在分享給你,請(qǐng)從我的錯(cuò)誤中學(xué)習(xí)。"誰(shuí)不喜歡袋熊呢?
這是Perl Weekly Challenge 373的第二題:列表分割。任務(wù)描述很直白——給定一個(gè)列表和一個(gè)非負(fù)整數(shù)n,把列表分成n個(gè)等份。如果n超過(guò)列表長(zhǎng)度,返回-1。
![]()
看幾個(gè)例子就懂了。5個(gè)元素分2份,商2余1,多出來(lái)的那個(gè)塞給第一份,得到(1,2,3)和(4,5)。6個(gè)元素分3份,整除,每份2個(gè)。10個(gè)元素分5份,每份2個(gè)。3個(gè)元素分4份?n比長(zhǎng)度大,輸出-1。
![]()
第6個(gè)例子有點(diǎn)意思:10個(gè)數(shù)字分7份,結(jié)果是((72,57), (89,55), (36,84), (10), (95), (99), (35))。前3份是2個(gè)元素,后4份各1個(gè)。分配規(guī)則是"靠前的 chunk 更大",余數(shù)從前面開(kāi)始消化。
作者在這里停頓了一下。通常這類題目給5個(gè)例子,這次給了6個(gè)。第6個(gè)例子看起來(lái)沒(méi)增加新信息,但那些數(shù)字——72,57,89,55,36,84,10,95,99,35——對(duì)應(yīng)ASCII碼是"H9Y7$T?_c#"。作者調(diào)侃:這很可能是項(xiàng)目經(jīng)理Kevin的密碼。Kevin,小心背后。
這個(gè)Kevin是誰(shuí)?前文埋了伏筆。"用-1而不是數(shù)組來(lái)處理無(wú)效輸入,這是代碼異味(code smell)。函數(shù)返回不同類型很難處理,容易出錯(cuò)。更一致的做法是拋異常,或者返回同類型的越界值,比如空數(shù)組或null引用。"但"那個(gè)只學(xué)了六個(gè)月JavaScript的混蛋Kevin因?yàn)槿箮шP(guān)系當(dāng)上了項(xiàng)目經(jīng)理,這就是我們的需求。"
怨氣沖天的注釋,藏在技術(shù)博客的括號(hào)里。
![]()
說(shuō)回代碼實(shí)現(xiàn)。核心算法幾步走:先算列表長(zhǎng)度,n太大直接返回-1。然后算每份基礎(chǔ)大小(向下取整),再算余數(shù)。兩個(gè)while循環(huán):第一個(gè)循環(huán)消耗余數(shù),每次取 chunk+1 個(gè)元素;第二個(gè)循環(huán)處理剩下的,每次取 chunk 個(gè)。都用splice從原數(shù)組頭部切,邊切邊push到結(jié)果數(shù)組。
作者特意討論了Perl的參數(shù)傳遞。Perl把參數(shù)打成扁平列表,這里選擇傳數(shù)組引用而非數(shù)組,兩個(gè)好處:一是消除歧義,讓$n的位置清晰;二是更高效——雖然對(duì)這個(gè)小腳本無(wú)所謂,但養(yǎng)成習(xí)慣很重要。
整個(gè)實(shí)現(xiàn)不到20行。簡(jiǎn)潔,但藏著對(duì)工程實(shí)踐的堅(jiān)持:類型一致性、接口清晰、防御式編程。以及,對(duì)Kevin的永恒吐槽。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.