迭代的努力–FizzBu​​zz

编辑它的价值,承认可能不是那么多。 我做了一点测试来扩展这个问题。

我写了两个函数来枚举FizzBu​​zz“系列”。

private static IEnumerable SimpleFizzBuzz( int start = 0, int end = int.MaxValue) { return Enumerable.Range(start, end).Select(i => i % 15 == 0 ? "fizzbuzz" : i % 3 == 0 ? "fizz" : i % 5 == 0 ? "buzz" : i.ToString(CultureInfo.InvariantCulture)); } 

和,

 private static IEnumerable OptimizedFizzBuzz( int start = 0, int end = int.MaxValue) { const int fizz = 3; const int buzz = 5; const string fizzString = "fizz"; const string buzzString = "buzz"; const string fizzBuzzString = fizzString + buzzString; var fizzer = start % fizz; var buzzer = start % buzz; if (fizzer == 0) { fizzer = fizz; } if (buzzer == 0) { buzzer = buzz; } for (var i = start; i <= end; i++) { if (buzzer == buzz) { if (fizzer == fizz) { yield return fizzBuzzString; buzzer = 1; fizzer = 1; continue; } yield return buzzString; buzzer = 1; fizzer++; continue; } if (fizzer == fizz) { yield return fizzString; buzzer++; fizzer = 1; continue; } yield return i.ToString(CultureInfo.InvariantCulture); fizzer++; buzzer++; } } 

我做了一点时间,在Release配置中编译,优化并从命令行运行。 超过10^8次迭代,没有实际报告每个项目的开销,我得到的结果接近于,

简单:14.5秒

优化:10秒

您会注意到“优化”function更快但更冗长。 它的行为可以通过改变其头部的常量来改变。


抱歉,如果这看起来有点微不足道。

考虑这个function。

 using System.Text; public string FizzBanger(int bound) { StringBuilder result = new StringBuilder(); for (int i = 1; i < bound; i++) { String line = String.Empty; if (i % 3 == 0) line += "fizz"; if (i % 5 == 0) line += "buzz"; if (String.IsNullOrEmpty(line)) line = i.ToString(); result.AppendLine(line.ToString()); } return result.ToString(); } 

输出看起来像

 1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 ... 

谁能想到一个更好的方法呢? 请考虑性能和可维护性。

 StringBuilder result = new StringBuilder(); 

对于一个固定的上限(100)我不会打扰这个,但好吧……

 StringBuilder line = new StringBuilder(); 

但是这个StringBuilder不仅冗余,而且效率非常低。 我甚至不需要基准来了解这一点。

 if (line.Length == 0) 

这只是模糊了逻辑(这应该实现“fizzbuzz”问题,对吗?)。 使逻辑明确。

请考虑性能和可维护性。

这是错误的方式。 可维护性第一,性能第二(如果有的话)。 你的代码实际上是非常低效的,但这是无关紧要的:有100次迭代 – 性能根本不重要。

此外,此代码具有哪些可维护性开销? 这是一个固定规格的玩具样品。 没有可维护性问题。 我甚至不想在这里有任何想法,Linq自动解决这个问题:

 return Enumerable.Range(1, bound - 1).Aggregate("", (accu, i) => string.Format("{0}\n{1}", accu, i % 15 == 0 ? "fizzbuzz" : i % 3 == 0 ? "fizz" : i % 5 == 0 ? "buzz" : i.ToString())); 

但我同意,如果不使用Aggregate函数,这可能会降低可读性。 所以让它更明确:

 var result = new StringBuilder(); for (int i = 1; i < bound; i++) result.AppendLine( i % 15 == 0 ? "fizzbuzz" : i % 3 == 0 ? "fizz" : i % 5 == 0 ? "buzz" : i.ToString()); return result.ToString(); 

其他一切都是过度工程化的。

假设您的代码只是您想要实现的示例…创建较少StringBuilders的提议:

 { StringBuilder result = new StringBuilder(); for (int i = 1; i < 101; i++) { var rest3 = i % 3; var rest5 = i % 5; if (rest3 == 0) result.Append("fizz"); if (rest5 == 0) result.Append("bang"); if (rest3 != 0 && rest5 != 0) result.Append(i); result.Append(System.Environment.NewLine); } } 

如果我们让事情变得更困难怎么办? 1)不允许分割或模运算; 2)循环必须跳过所有不必要的迭代。 这是答案:

 int n3 = 3; int n5 = 5; int i = 3; while (i <= 100) { Console.Write(i.ToString() + " - "); if (i == n3) { Console.Write("fizz"); n3 = n3 + 3; } if (i == n5) { Console.Write("buzz"); n5 = n5 + 5; } Console.WriteLine(); i = n3 < n5 ? n3 : n5; }