0

编辑对于它的价值,承认可能没有那么多。我做了一个小测试来扩展这个问题。

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

private static IEnumerable<string> 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<string> 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++;
    }
}

我做了一些计时,在发布配置中编译,优化并从命令行运行。在10^8迭代过程中,没有实际报告每个项目的开销,我得到的结果近似于,

简单:14.5 秒

优化:10 秒

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


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

考虑这个函数。

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
...

有人能想到更好的方法吗?请同时考虑性能和可维护性。

4

3 回答 3

12
StringBuilder result = new StringBuilder();

对于固定的上限 (100),我不会为此烦恼,但可以……</p>

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();

其他一切都是过度工程。

于 2011-04-14T09:56:25.553 回答
3

假设您的代码只是您想要实现的目标的一个示例......创建更少 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);
      }
}
于 2011-04-14T10:03:47.563 回答
0

如果我们让事情变得更困难怎么办?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;
}
于 2014-12-22T11:12:44.703 回答