开篇先听歌。"Let's Dance to Joy Division",英国乐队Wombat的歌。歌词意外贴合编程博客:"我昨晚想通了一件事,改变了这个小男孩的脑子,花了22年才悟出的小建议,现在分享给你,请从我的错误中学习。"谁不喜欢袋熊呢?
这是Perl Weekly Challenge 373的第二题:列表分割。任务描述很直白——给定一个列表和一个非负整数n,把列表分成n个等份。如果n超过列表长度,返回-1。
看几个例子就懂了。5个元素分2份,商2余1,多出来的那个塞给第一份,得到(1,2,3)和(4,5)。6个元素分3份,整除,每份2个。10个元素分5份,每份2个。3个元素分4份?n比长度大,输出-1。
第6个例子有点意思:10个数字分7份,结果是((72,57), (89,55), (36,84), (10), (95), (99), (35))。前3份是2个元素,后4份各1个。分配规则是"靠前的 chunk 更大",余数从前面开始消化。
作者在这里停顿了一下。通常这类题目给5个例子,这次给了6个。第6个例子看起来没增加新信息,但那些数字——72,57,89,55,36,84,10,95,99,35——对应ASCII码是"H9Y7$T?_c#"。作者调侃:这很可能是项目经理Kevin的密码。Kevin,小心背后。
这个Kevin是谁?前文埋了伏笔。"用-1而不是数组来处理无效输入,这是代码异味(code smell)。函数返回不同类型很难处理,容易出错。更一致的做法是抛异常,或者返回同类型的越界值,比如空数组或null引用。"但"那个只学了六个月JavaScript的混蛋Kevin因为裙带关系当上了项目经理,这就是我们的需求。"
怨气冲天的注释,藏在技术博客的括号里。
说回代码实现。核心算法几步走:先算列表长度,n太大直接返回-1。然后算每份基础大小(向下取整),再算余数。两个while循环:第一个循环消耗余数,每次取 chunk+1 个元素;第二个循环处理剩下的,每次取 chunk 个。都用splice从原数组头部切,边切边push到结果数组。
作者特意讨论了Perl的参数传递。Perl把参数打成扁平列表,这里选择传数组引用而非数组,两个好处:一是消除歧义,让$n的位置清晰;二是更高效——虽然对这个小脚本无所谓,但养成习惯很重要。
整个实现不到20行。简洁,但藏着对工程实践的坚持:类型一致性、接口清晰、防御式编程。以及,对Kevin的永恒吐槽。
热门跟贴