我确定这里的每个人都知道FizzBu​​zz是什么。我想对我的解决方案提出建设性的批评。

我是一个整体编程的初学者,这不是我的第一个解决方案,但这是我认为的最佳解决方案。我想看看这是否是一个合理的解决方案,或者只是一个很糟糕的解决方案。

这是您的标准FizzBu​​zz输出。

评论

对于如此小的简单功能,很难提出建设性的批评。这是一个合理的解决方案,我唯一能认错的就是我非常挑剔或个人喜好。

您可以使用var output = i;然后删除最后的else块。

一个可能的问题是您依赖于使用3和5的标准Fizzbuzz(因此将3 * 5检查为15)。有人可能会使用2和4进行测试,以查看您是否陷入了检查8的陷阱。

最好包括您遵循的实际规格。 FizzBu​​zz解决方案看起来不错。任何其他要点都与您如何遵循规范的细微差别有关。如果您真的想花哨的话,可以不用算法的显式“ FizzBu​​zz”部分。

这个问题正在meta上讨论。

#1 楼


我想看看这是否是一个合理的解决方案,或者只是一个很糟糕的解决方案。

我不会说这是“可怕的”-主要是因为它有效并且不能似乎效率很低。但是,可以进行一些改进。


使用严格相等比较-即比较值时的===。这样就不需要转换类型。


样式指南考虑遵循样式指南。许多常见的样式指南建议用空格分隔关键字-例如if (而不是if(


使用一致的缩进for循环中的第一行和最后一行不缩进,而它们之间的其他行则缩进,尽管您的代码可能是这种情况被正确缩进,但是当您在此处粘贴时,由于markdown格式而被丢弃...


将抽象逻辑转换为函数正如Paul的回答所建议的:您可以将核心逻辑转换为函数该函数返回输出,但不处理输出值(例如,输出到控制台)。这使此类代码具有原子性且可测试-与“单一职责原则”一致。同样,return语句可以消除函数中对else关键字的需求。一个缺点是,每次迭代调用一个函数可能会减慢运算速度,但对于一组1到100的数字来说应该可以忽略不计。


更新的代码
请考虑以下修改的代码,利用上述反馈。我还在最近的问题:具有动态高度容器的Fizzbuzz中包含的代码中使用了此代码。
注意:代码段中的嵌入式控制台被截断为〜50行,但是完整的控制台日志应该在浏览器控制台中可见。



 function fizzBuzz(value) {
    if (value % 15 === 0) { return "FizzBuzz"; }
    if (value % 3 === 0) { return "Fizz"; }
    if (value % 5 === 0) { return "Buzz"; }
    return value;
}
for (let i = 1; i <= 100; i++) {
    console.log(fizzBuzz(i));
} 




我确实考虑过的一种选择是减少模运算的数量,附加到输出字符串而不是输出它。如果您尝试优化速度,则可能不适合采用这种方法,因为追加到字符串可能比执行额外的一对模运算慢得多。尝试在此jsPerf测试中进行比较。



 function fizzBuzz(value) {
    let output = "";
    if (value % 3 === 0) { output += "Fizz"; }
    if (value % 5 === 0) { output += "Buzz"; }
    return output || value;
}
for (let i = 1; i <= 100; i++) {
    console.log(fizzBuzz(i));
} 




评论


\ $ \ begingroup \ $
还有“从不使用分号”学校。 blog.izs.me/2010/12/…feross.org/never-use-semicolons
\ $ \ endgroup \ $
–Džuris
19年1月8日在22:01

\ $ \ begingroup \ $
@CaseyB当OP是初学者时,我不认为像这样的微优化争论是个好主意。
\ $ \ endgroup \ $
–声乐
19年1月9日在9:43

\ $ \ begingroup \ $
@Voile一百万%。即使这是可用于生产的企业级,基于云的微服务™,可读性和可维护性始终是头等大事。老实说,对JavaScript FizzBu​​zz进行微优化的概念非常有趣。
\ $ \ endgroup \ $
–迈克尔
19年1月9日在10:34

\ $ \ begingroup \ $
@Michael FizzBu​​zz企业版与众不同。 :P但是FWIW,我相信Casey只是对答案本身最初提出的微优化提出了反对意见。
\ $ \ endgroup \ $
–玛蒂·乌尔哈克
19年1月9日,12:05

\ $ \ begingroup \ $
@MateenUlhaq 260问题……伙计们,他们确实需要对其进行重构,安排UAT并使用看板。
\ $ \ endgroup \ $
– Juha Untinen
19年1月9日在13:10

#2 楼

问题之一是不需要检查i % 15(即i是3和5的倍数)的情况。您重复了3和5的概念,并且重复了Fizz和Buzz的概念。

当前这不是什么大问题,但是假设有人要求您扩展程序以在打印“ Jazz”时i是7的倍数。使用您当前的策略,我们现在需要i是以下项的倍数的情况:


3
5
7
3和5
3和7
5和7
3和5和7

看起来像这样:




 for(var i = 1;i <= 100; i++) {
    var output = "";

    if(i % 105 == 0) {output = "FizzBuzzJazz"}
    else if(i % 15 == 0) {output = "FizzBuzz"}
    else if(i % 35 == 0) {output = "BuzzJazz"}
    else if(i % 21 == 0) {output = "FizzJazz"}
    else if(i % 3 == 0) {output = "Fizz"}
    else if(i % 5 == 0) {output = "Buzz"}
    else if(i % 7 == 0) {output = "Jazz"}
    else { output = i; }

    console.log(output);
} 





看看失控有多快?如果添加第四个单词,情况会变得更糟。 >



 output 





(我已修正了Sam的回答中建议的其他几件事)

如果您是初学者,是用作for(var i = 1; i <= 100; i++) { var output = ""; if (i % 3 === 0) {output += "Fizz";} if (i % 5 === 0) {output += "Buzz";} if (i % 7 === 0) {output += "Jazz";} console.log(output === "" ? i : output); }的自变量或称为条件或三元运算符的表达式。我们的说,如果输出为空(即不是3、5或7的倍数),则打印console.log,否则打印我们复合的字符串。

三元运算符总是可以替换为如果您还不满意的话,则为if语句。

评论


\ $ \ begingroup \ $
@PatrickRoberts是。除了这些之外,我还希望更多地专注于解决问题的方法。 Buuut我确实纠正了所有其他问题(我无能为力),所以是的,我也进行了更改。谢谢
\ $ \ endgroup \ $
–迈克尔
19年1月10日在16:15

\ $ \ begingroup \ $
您忘记了三元表达式中的相等性。我试图编辑自己,但只能编辑至少6个字符:|
\ $ \ endgroup \ $
–帕特里克·罗伯茨(Patrick Roberts)
19年1月10日在16:23

\ $ \ begingroup \ $
对于3、5,Fizz和Buzz的重复,您没有错,但是在改进方面有偏见。考虑一个更改,其中“ FizzBu​​zz”现在必须为13的倍数,或者更改为15的倍数必须为“ Floopidoops”。在这些情况下,OP的代码比您的代码更容易更改。这里的问题是您是否推断倍数(3、5、15)之间的关系以及“ Fizz”,“ Buzz”和“ FizzBu​​zz”之间的关系是因果关系还是巧合。您需要进行详细说明(=分析),然后才能做出正确的判断。
\ $ \ endgroup \ $
–更
19 Nov 20 '14:43



#3 楼

我认为这很好,尽管有些人喜欢早点返回,而不是使用一系列的if..else。例如:

function calc(i) {
  if(i % 15 == 0) return "FizzBuzz";
  if(i % 3 == 0) return "Fizz";
  if(i % 5 == 0) return "Buzz";
  return i;
}

for(var i=1;i<=100;i++) {
  console.log(calc(i));
}


评论


\ $ \ begingroup \ $
“早退”通常被称为“多个出口点”,有时被认为是不良做法。
\ $ \ endgroup \ $
– Moby磁盘
19年1月9日在18:59

\ $ \ begingroup \ $
“提早归还”通常称为“验证”,通常被认为是良好做法。
\ $ \ endgroup \ $
– Nurettin
19年1月10日在11:22

\ $ \ begingroup \ $
早归的人有很多名字,人们对自己的方式是否最好感到非常困惑。
\ $ \ endgroup \ $
– Tim B
19年1月10日在17:25

\ $ \ begingroup \ $
@MobyDisk该建议最初来自于Assembly,并被称为“退出的地方”,而不是“退出的地方”。这样就消除了“一直以来都是这样,所以一定有一个理由”的说法。在将此建议的修订版本应用于特定方案之前,请检查它是否确实有意义。在这种情况下,不是。
\ $ \ endgroup \ $
– wizzwizz4
19年1月12日在12:44

#4 楼

扩展迈克尔的答案,您还可以创建一个包含所有想要的单词的对象,关键是输入内容必须被其整除的数字,以使其更具动态性,并为将来提供更多证据(添加新的内容要容易得多)进入对象而不是添加更多的代码行),并且对象本身也可以动态生成。




 divisions = {3: "Fizz", 5: "Buzz", 7: "Jazz"};

for(var i = 1; i <= 100; i++) {
    var output = "";

    for (var x in divisions) {
        if(i % x == 0) output += divisions[x]; 
    }

    console.log(output == "" ? i : output);
} 




评论


\ $ \ begingroup \ $
您如何确保Fizz始终在Buzz之前出现?与PHP不同,在JavaScript中,对象的键不是确定性的。
\ $ \ endgroup \ $
–罗兰·伊利格(Roland Illig)
19年11月20日在1:37

\ $ \ begingroup \ $
@RolandIllig:随着数据结构的更改,divisions.sort(d => d.Value)(或其任何变体)修复了该问题。
\ $ \ endgroup \ $
–更
19年11月20日14:48



\ $ \ begingroup \ $
@Flater是的,我知道。我想从脾气暴躁的人那里确切听到,因为在当前状态下答案是错误的。
\ $ \ endgroup \ $
–罗兰·伊利格(Roland Illig)
19年11月20日在18:56

\ $ \ begingroup \ $
@RolandIllig对不起,我不太了解您的要求。
\ $ \ endgroup \ $
–GrumpyCrouton
19/12/2在14:29

\ $ \ begingroup \ $
仅当按顺序应用除数和单词时,您的代码才有效。通常,不指定单词的顺序。因此,您的代码“偶然”起作用,而不是设计使然。
\ $ \ endgroup \ $
–罗兰·伊利格(Roland Illig)
19/12/2在18:10

#5 楼

在实施算法时,至少起初我倾向于有点“文学家”。因此,我将从此开始,然后从那里进行优化。我喜欢这样可以使事情保持清晰。

const calcFizzBuzz = function(num) {
  let result = "";
  if (num % 3 === 0) {
    result += "Fizz";
    if (num % 5 === 0) {
      result += "Buzz";
    }
  } 
  else if (num % 5 === 0) {
    result += "Buzz";
  } 
  else {
    result = num;
  }
  return result;
}

for (let i = 0; i < 100; i++) {
  console.log(calcFizzBuzz(i));
}


评论


\ $ \ begingroup \ $
重复if(num%5 === 0){result + =“ Buzz”}显然是多余的。为什么您更喜欢这样写?
\ $ \ endgroup \ $
–罗兰·伊利格(Roland Illig)
19年11月20日在1:43

#6 楼

从维护的角度来看,我认为最好检查3和5而不是检查15。检查15的问题是,从现在起6个月后返回代码时,您不会意识到自己当某些东西可以同时被3和5整除时,它们只是在打印fizzbuzz。这在将来可能很重要,但是我认为在采访中值得讨论。

#7 楼

尽管您的代码很好,但是要看的另一件事是代码发生了除法,除法是计算上昂贵的操作,正如@Michael所建议的那样,它是多余的。因此,请始终尽量减少代码中的乘法和除法运算。

您提到您是一名初学者。我相信这是个好习惯,开始让自己熟悉计算复杂性等主题。

在这里查找数学函数的计算复杂性

评论


\ $ \ begingroup \ $
虽然我认为对于一个入门的程序员来说,学习诸如内存管理之类的东西还为时过早(假设这是他们的第一个实际程序之一),但我认为这是一个不错的答案!
\ $ \ endgroup \ $
–怀旧
19年1月9日在20:10

\ $ \ begingroup \ $
该建议大喊“过早的优化”。除法不是一项昂贵的操作。这种添加要贵一些,但在当今的计算机上并没有真正昂贵。您的手机可以在几分之一秒内完成数百万次的分割。到目前为止,字符串连接要昂贵得多。代码质量中最重要的指标是可读性。另外,如果您在谈论计算复杂性,则应注意,所做的更改根本不会改变复杂性。
\ $ \ endgroup \ $
–苏丹
19年1月9日在23:37



\ $ \ begingroup \ $
底层除法算法的理论计算复杂度实际上无关紧要。
\ $ \ endgroup \ $
–疯狂
19年1月10日在3:05



\ $ \ begingroup \ $
@Sulthan主题的计算复杂度没有考虑到机器可以执行多少个操作,而是考虑了解决一个问题需要多少个操作/步骤。加法器的CC是线性的,除法是二次的。仅将3和5相除会改变复杂度,并且可以将这些结果保存在bool变量中,该变量可以以恒定的时间复杂度进行评估。
\ $ \ endgroup \ $
– Hemanshu
19年1月10日在13:58



\ $ \ begingroup \ $
在现代CPU整数除法上需要1个CPU周期,%的JS版本要更长一些。 JS会尽可能使用32位带符号的整数,因此与仅调用函数相比,该操作无关紧要。顺便说一句,链接的计算复杂度页面与CPU ALU和FLU如何处理基本数学运算无关。
\ $ \ endgroup \ $
– Blindman67
19年1月10日在14:08