我是一个整体编程的初学者,这不是我的第一个解决方案,但这是我认为的最佳解决方案。我想看看这是否是一个合理的解决方案,或者只是一个很糟糕的解决方案。
这是您的标准FizzBuzz输出。
#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 FizzBuzz进行微优化的概念非常有趣。
\ $ \ endgroup \ $
–迈克尔
19年1月9日在10:34
\ $ \ begingroup \ $
@Michael FizzBuzz企业版与众不同。 :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的重复,您没有错,但是在改进方面有偏见。考虑一个更改,其中“ FizzBuzz”现在必须为13的倍数,或者更改为15的倍数必须为“ Floopidoops”。在这些情况下,OP的代码比您的代码更容易更改。这里的问题是您是否推断倍数(3、5、15)之间的关系以及“ Fizz”,“ Buzz”和“ FizzBuzz”之间的关系是因果关系还是巧合。您需要进行详细说明(=分析),然后才能做出正确的判断。
\ $ \ 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
评论
对于如此小的简单功能,很难提出建设性的批评。这是一个合理的解决方案,我唯一能认错的就是我非常挑剔或个人喜好。您可以使用var output = i;然后删除最后的else块。
一个可能的问题是您依赖于使用3和5的标准Fizzbuzz(因此将3 * 5检查为15)。有人可能会使用2和4进行测试,以查看您是否陷入了检查8的陷阱。
最好包括您遵循的实际规格。 FizzBuzz解决方案看起来不错。任何其他要点都与您如何遵循规范的细微差别有关。如果您真的想花哨的话,可以不用算法的显式“ FizzBuzz”部分。
这个问题正在meta上讨论。