一段程序的多种写法


问题

在某技术群里,有人问(截取的原话):

如果是 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分。

总结

代码是写给人看的!代码是写给人看的!代码是写给人看的!

一定要测试!!一定要测试!!一定要测试!!

 

番外

我有个同事,写代码就从来都不测试,发上线就有报警短信。。。。。。。。。。。。。。。


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注