问题
在某技术群里,有人问(截取的原话):
如果是 9 ,就分成 3,3,3
如果一个数字是 10 ,就分成 3, 3, 4
就是除不尽的时候,就把多余的数,分给最后一个
有可能是 100 / 3 = 33 + 33 + 34
有可能是 100/2 = 50 + 50
总数 = N + N +… +(N +余数)
看到这里,已经很明确了,这是一个非常简单的需求。然后,群里各位大神就开始飙技能了。
答案
第一位 作者:蜃楼寻梦(64*****98) :
function test($digit , $copies) { if ($digit % $copies == 0) { return array_fill(0 , $copies , $digit / $copies); }else{ $size = floor($digit / $copies); $returned = array_fill(0 , $copies , $size); $returned[$copies-1] = $digit - $size * ($copies - 1); return $returned; } } print_r(test(100 , 3)); print_r(test(100 , 5));
第二位(原图摘抄)作者:viile(88*****3):
function test($num,$quantity){ if(!$num || !$quantity){ return; }else{ $tmp = ($num - ($num % $quantity)) / $quantity; echo $tmp; test($num - $tmp ,$quantity - 1); } }
第三位(其实是第一个发出来单元测试代码的,代码不完整)作者:生活没有如果<*******@qq.com>:
public function _any($c) { $div = $c%3; $a = ($c-$div)/3; $b = $a+$div;
第二位同学,又写了一个版本,并说:一口气上五楼,不费劲。。。看看代码:
$result = function($num,$quantity) use (&$result){ if(!$num || !$quantity){ return; }else{ $result($num - (($num - ($num % $quantity)) / $quantity) , $quantity - 1); } }; var_dump($result(10, 4));
这个版本一出来,我就看不下去了,开始加入讨论:
viile(88*****3) 18:04:56
还可以这样写
viile(88*****3) 18:05:02
一口气上五楼 不费力
小感动(65*****07) 18:08:23 【题主】
还能这么写。。。
Nemo<****@vip.qq.com> 18:08:24【本人】
看不懂。。 不是好写法~
Nemo<****@vip.qq.com> 18:09:26
程序不是写给机器看的。。 所以,选择一个一眼就看懂这段程序是干啥用的。。 最好~
Heart stops beating<*****@ok.de> 18:10:13
。感觉你说的不对
Heart stops beating<*****@ok.de> 18:10:51
你看不懂只能证明你不会而认为它不好
Nemo<****@vip.qq.com> 18:12:45
呵呵。。蜃楼寻梦(64*****98) 18:17:02
@viile 你这个写法还是在递归..
蜃楼寻梦(64*****98) 18:17:20
【截图指出递归在哪】
viile(88*****3) 18:17:37
对啊,本来就是递归
蜃楼寻梦(64*****98) 18:18:15
那种简单的算法 不需要递归的.Nemo<****@vip.qq.com> 18:18:47
这种程序员,虽说牛逼,但是写出来的东西,boss不喜欢。。。
Heart stops beating<*****@ok.de> 18:19:18
Boss看不懂。才会觉得你牛逼。
这时,来了位老船长,给出如下第五种写法 作者:老船长(45*****45) :
private function testVal($a, $b = 3) { $i = intval($a / $b); $v = array_fill(0, $b, $i); $v[$b - 1] += $a % $i; return $v; }
第六种写法(js版) 作者:小感动(65*****07) :
function numSplice(num, cnt){ var sArr = []; var avgNum = Math.floor(num/cnt); for(i=1; i<=cnt; i++){ if(i==cnt){ avgNum = avgNum + (num - avgNum * cnt); } sArr.push(avgNum); } console.log(sArr); }
这时第二位作者又说道:
viile(88*****3) 18:36:13
代码优雅也是很重要的
然后,以我给出了最后一版写法剧终了。。。(没人搭话了。。 )代码是这样的:
function splitNumber($number, $piece){ $pieceValue = (int)($number / $piece); return array_merge(array_fill(0, $piece - 1, $pieceValue), array($pieceValue + $number % $pieceValue)); } $number = 10; $piece = 3; var_dump(splitNumber($number, $piece));
点评
贴了这么多,不是记流水账,是要讨论下,到底要怎么写好一段代码?
1
细看第一位同学的写法,中规中矩,还考虑了整除的情况,直接就不用额外计算最后一个元素的值了。但是,计算非整除的情况下,最后一个元素被赋值了两次,第二次的覆盖显然会对读代码的人造成一定心理波动(第一次赋值是想干啥?)。变量命名上有一些词不达意。测试test(10,3);test(10,4) 结果均正确。
如果是面试题(讨论中有人问到这是面试题么?答案:不是),这答案,可以给80分。
2
再看第二位同学,运行了test(10,3)结果是对的,运行下test(10,4)结果是错的(2,2,3,3)。还用了递归,一眼你觉得看不出来他是要干啥。
答案都错了,0分。
3
第三位同学的测试代码我就不发了,明显属于不理解题意那伙的。。。负分。
4
第二位同学的第二版,无论我怎么运行,结果都是null。。。已然负分。再说说这彰显技能的写法:匿名函数、递归。。。还有同学附和着说“你看不懂只能证明你不会而认为它不好” “Boss看不懂。才会觉得你牛逼。”。。。
5
再说说老船长给出的第五种写法,运行testVal(10,3)结果是正确的,testVal(10,4)结果是错的,给出(2,2,2,2)。变量名用i、a、b、v更是让人无语。
如果是面试,这题给20分。(变量命名真的是非常重要的好么!)
js版是很好的一个版本,各种正常数据均能得到正确结果。作者也说了,js没有相关方法,才无奈用循环的。变量命名有点儿啰嗦,并存在简写。这答案90分。
6
最后,说下我给出的版本,当时工作略忙(QA提给我的各种bug都是客户端的问题,并且还都不写清楚问题场景数据,让我猜?),没有测试更多的结果,当运行splitNumber(10,4)的时候,给出的答案也是错的(2,2,2,2)。当时写的时候,还真想到了最后一个元素的写法,是用总数减之前所有数呢?还是平均数+余数呢?纠结了一下,用了后者,显然,我变量写错了。。。
纠正下写法:
function splitNumber($number, $piece){ $pieceValue = (int)($number / $piece); return array_merge(array_fill(0, $piece - 1, $pieceValue), array($pieceValue + $number % $piece)); // $number % $piece 才是余数 }
从函数、变量命名、代码逻辑上,这答案,应该值90分。但是,由于没有测试更多数据,导致有低级错误未发现。最终也就值0分。
总结
代码是写给人看的!代码是写给人看的!代码是写给人看的!
一定要测试!!一定要测试!!一定要测试!!
番外
我有个同事,写代码就从来都不测试,发上线就有报警短信。。。。。。。。。。。。。。。