Написание FizzBuzz

читая ужасы кодирования, я только что наткнулся на шипение в другой раз.

исходный пост здесь:кодирование ужас: почему не могут программисты.. Программа?

для тех, кто не знает: FizzBuzz-довольно популярная детская игра. Считая от 1 до 100, и каждый раз, когда число делится на 3, вызывая "Fizz", каждый раз число делится на 5, вызывая "жужжание" и каждый раз, когда число делится на 3 и 5, вызывая " FizzBuzz вместо номер

но на этот раз я просто начал кодировать его. Это была минутная работа., но есть несколько вещей, которые мне не нравятся.

вот мой код

public void DoFizzBuzz()
{
    var combinations = new Tuple<int, string>[] 
    { 
        new Tuple<int, string> (3, "Fizz"), 
        new Tuple<int, string> (5, "Buzz"), 
    };

    for (int i = 1; i <= 100; ++i)
    {
        bool found = false;

        foreach (var comb in combinations)
        {
            if (i % comb.Item1 == 0)
            {
                found = true;
                Console.Write(comb.Item2);
            }
        }

        if (!found)
        {
            Console.Write(i);
        }

        Console.Write(Environment.NewLine);
    }
}

Итак, мои вопросы:

  1. Как избавиться от найденного bool?
  2. есть ли лучший способ проверки чем цикл foreach?

30 ответов


Я думаю, что вы пытаетесь выполнить общее решение FizzBuzz, которое будет работать для любого количества комбинаций чисел и слов.

у вас хорошее начало - я думаю, что могу ответить на ваши вопросы с помощью этого примера:

public void DoFizzBuzz()
{
    var combinations = new List<Tuple<int, string>>
    { 
        new Tuple<int, string> (3, "Fizz"), 
        new Tuple<int, string> (5, "Buzz"), 
    };

    Func<int, int, bool> isMatch = (i, comb) => i % comb == 0;
    for (int i = 1; i <= 100; i++)
    {
        Console.Write(i);

        var matchingCombs = combinations.Where(c => isMatch(i, c.Item1)).ToList();
        if (matchingCombs.Any())
        {
            Console.Write(string.Join("", matchingCombs.Select(c => c.Item2)));
        }
        else
        {
            Console.Write(i);
        }
        Console.Write(Environment.NewLine);
    }
}

на практике, вы бы пройти combinations в методе, но я включил его внутрь, чтобы быть кратким.


Я думаю, что ваша реализация является излишне сложным. Это делает работу и легче понять:

public void DoFizzBuzz()
{
    for (int i = 1; i <= 100; i++)
    {
        bool fizz = i % 3 == 0;
        bool buzz = i % 5 == 0;
        if (fizz && buzz)
            Console.WriteLine ("FizzBuzz");
        else if (fizz)
            Console.WriteLine ("Fizz");
        else if (buzz)
            Console.WriteLine ("Buzz");
        else
            Console.WriteLine (i);
    }
}

воспользоваться условной спецификаторы формата, чтобы получить красиво играл версия:

public void DoFizzBuzz()
{
    for(int i=1;i<101;i++)Console.WriteLine("{0:#;}{1:;;Fizz}{2:;;Buzz}",i%3*i%5==0?0:i,i%3,i%5);
}

3-й редактировать:

вот один из способов "избавиться от bool" из вашей версии (то есть заменить цикл for в вашем исходном вопросе этим):

for (int i = 1; i <= 100; i++)
{
  var x = combinations.Where(n => i % n.Item1 == 0);

  if (x.Count() == 0)
    Console.Write(i);
  else
    Console.Write(string.Join("",x.Select(e => e.Item2)));

  Console.Write(Environment.NewLine);
}

до ответа:

для чистого решения c# проверьте кита Томпсона решение.

using System;
class FizzBuzz {
    static void Main() {
        for (int n = 1; n <= 100; n ++) {
            if (n % 15 == 0) {
                Console.WriteLine("FizzBuzz");
            }
            else if (n % 3 == 0) {
                Console.WriteLine("Fizz");
            }
            else if (n % 5 == 0) {
                Console.WriteLine("Buzz");
            }
            else {
                Console.WriteLine(n);
            }
        }
    }
}

Я немного поработал над FixBuzz, используя linq. Это решения, которые я придумал - я считаю, что они представляют собой лучший способ выразить решение этой проблемы использование Linq. (GitHub)

using System;
using System.Linq;

class FizzBuzz {
  static void Main() {
    var list = Enumerable.Range(1,100)
                .Select(n => {
                      if (n % 15 == 0) {
                        return "FizzBuzz";
                      }
                      if (n % 3 == 0) {
                        return "Fizz";
                      }
                      if (n % 5 == 0) {
                        return "Buzz";
                      }
                      return n.ToString();
                    });

    foreach(string item in list)
      Console.WriteLine(item);
  }
}

и сумасшедшая версия одной строки:

using System;
using System.Linq;

class FizzBuzz {
    static void Main() {
      Console.WriteLine(
      String.Join(
        Environment.NewLine,
        Enumerable.Range(1, 100)
          .Select(n => n % 15 == 0 ? "FizzBuzz" 
                     : n % 3 == 0 ? "Fizz" 
                     : n % 5 == 0 ? "Buzz" 
                     : n.ToString())
      ));
    }
}

развернутый для максимальной эффективности. Эта программа может outfizzbuzz все остальные.

public void FizzBuzz()
{
    const string FIZZ = "Fizz";
    const string BUZZ = "Buzz";
    const string FIZZBUZZ = "FizzBuzz";

    int i = 0;
    while (i < 150)
    {
        Console.WriteLine(++i);
        Console.WriteLine(++i);
        Console.WriteLine(FIZZ); ++i;
        Console.WriteLine(++i);
        Console.WriteLine(BUZZ); ++i;
        Console.WriteLine(FIZZ); ++i;
        Console.WriteLine(++i);
        Console.WriteLine(++i);
        Console.WriteLine(FIZZ); ++i;
        Console.WriteLine(BUZZ); ++i;
        Console.WriteLine(++i);
        Console.WriteLine(FIZZ); ++i;
        Console.WriteLine(++i);
        Console.WriteLine(++i);
        Console.WriteLine(FIZZBUZZ); ++i;
    }
}

public void DoFizzBuzz()
{
    for (int i = 1; i <= 100; i++)
    {
        if (i % 3 == 0)
            Console.Write("Fizz");
        if (i % 5 == 0)
            Console.Write("Buzz");
        if (!(i % 3 == 0 || i % 5 == 0))
            Console.Write(i);

        Console.Write(Environment.NewLine);
    }
}

Это избавляется от bool found, но заставляет вас делать дубликат оценки. Он немного отличается от некоторых других ответов, использующих i % 15 == 0 для квалификации FizzBuzz. Действительно ли это лучше для дебатов. Тем не менее, это разные путь.


кто-нибудь уже сделал это?

Enumerable.Range(1, 100).Select(x =>
                (x % 15 == 0) ? "FIZZBUZZ"
                : (x % 5 == 0) ? "BUZZ"
                : (x % 3 == 0) ? "FIZZ"
                : x.ToString()
                )
                .ToList()
                .ForEach(console.WriteLine);

Я думаю, что вы начали сложный путь. Улучшить этот код было бы сложнее. Вы можете использовать переменную temp для отслеживания и отображения этой переменной в конце проверки FizzBuzz. Ниже приведен код, и вы также можете посмотреть эту деталь c# FizzBuzz youtube video (http://www.youtube.com/watch?v=OX5TM3q-JQg ), который объясняет, как реализуется приведенный ниже код.

    for (int j = 1; j <= 100; j++)
    {
    string Output = "";

    if (j % 3 == 0) Output = "Fizz";// Divisible by 3 --> Fizz

    if (j % 5 == 0) Output += "Buzz"; // Divisible by 5 --> Buzz

    if (Output == "") Output = j.ToString(); // If none then --> number

    Console.WriteLine(Output); // Finally print the complete output
    }

добавит мои 5 центов к решению Linq. Все используют Select, который в основном является функцией карты. Функция IMHO foldl подходит лучше для решения этой викторины:

Console.WriteLine(
                Enumerable
                .Range(1, 100)
                .Aggregate(new StringBuilder(), (builder, i)
                    => i % 15 == 0 ? builder.AppendLine("FizzBuzz")
                     : i % 3 == 0 ? builder.AppendLine("Fizz")
                     : i % 5 == 0 ? builder.AppendLine("Buzz")
                     : builder.AppendLine(i.ToString()))
                .ToString());

Linq:

Enumerable.Range(1, 100).ToList().ForEach(i => Console.WriteLine( i % 3 * i % 5 == 0 ? (i % 3 == 0 ? "Fizz" : "") + (i % 5 == 0 ? "Buzz" : "") : i.ToString()));

хорошо, какого черта, вот решение, которое мне понравилось:)

public void DoFizzBuzz()
{
    for (int i = 1; i <= 100; ++i)
    {
        bool isDivisibleByThree = i % 3 == 0;
        bool isDivisibleByFive = i % 5 == 0;

        if (isDivisibleByThree || isDivisibleByFive)
        {
            if (isDivisibleByThree)
                cout << "Fizz";

            if (isDivisibleByFive)
                cout << "Buzz";
        }
        else
        {
            cout << i;
        }
        cout << endl;
    }
}

очевидно, что это не самое быстрое решение, но мне это нравится, потому что оно подчеркивает читаемость и делает случай "FizzBuzz" больше не частным случаем, а чем-то, что будет происходить естественно через путь кода.

в конце концов, что мне больше всего нравится в этом вопросе, когда он возникает, так это то, что мы видим, сколько разных решений ppl может придумать.


вы хотите, вероятно, сделать его настраиваемым, но вопрос в том, что должно быть сделано настраиваемым - мы этого не знаем. Возможно, мы должны сделать настраиваемый весь цикл (FizzBuzz имеет цикл). Вот очень маленькая и забавная версия с настраиваемым циклом:

string[] fizzBuzzCycle = 
    "FizzBuzz,{0},{0},Fizz,{0},Buzz,Fizz,{0},{0},Fizz,Buzz,{0},Fizz,{0},{0}"
    .Split(',');

for (int i = 1; i <= 100; i++)
    Console.WriteLine(fizzBuzzCycle[i%fizzBuzzCycle.Length], i);

поэтому, если строки или весь цикл должны быть изменены, это легко изменить. Но вы просто не знаете что сделать настраиваемыми. Возможно, изменится условие: "для простых чисел print Pizz" и для этой модификации решение @ThomasLevesque лучше, потому что его легче изменить.


Не самый эффективный, но с помощью C#-6 интерполяция строк:

void Main()
{
    for (int i = 1; i <= 100; i++)
    {
       Console.WriteLine($"{(i % 15 == 0 ? "FizzBuzz" : 
                             i % 3 == 0 ? "Fizz" : 
                             i % 5 == 0 ? "Buzz" : i.ToString())}");
    }
}

С вводом Роба H и Джейкоба Кралла вот что у меня есть на данный момент. Возможно, я буду играть с этим в будущем... просто хотел его обеспечить.

public void DoFizzBuzz()
{
    // expect this to come in as parameter
    var combinations = new Tuple<int, string>[] 
    { 
        new Tuple<int, string> (3, "Fizz"), 
        new Tuple<int, string> (5, "Buzz"), 
    };

    Func<int, int, bool> isMatch = (i, comb) => i % comb == 0;

    // expect the borders 1, 100 to come in as parameters
    for (int i = 1; i <= 100; ++i)
    {
        var matchingCombs = combinations.Where(c => isMatch(i, c.Item1)).DefaultIfEmpty(new Tuple<int, string>(i, i.ToString())).Aggregate((v, w) => new Tuple<int, string>(v.Item1, v.Item2 + w.Item2)).Item2;
        Console.WriteLine(matchingCombs);
    }
}

на мой взгляд, проблема FizzBuzz всегда представлена как вызов интервьюируемому, чтобы слово FizzBuzz появилось без явной печати. Вот мое решение на C#.

internal void PrintFizzBuzzAlternative(int num)
{
    if (num % 5 == 0)
        Console.Write("Fizz");
    if (num % 3 == 0)
        Console.Write("Buzz");
    if (num % 5 != 0 && num % 3 != 0)
        Console.Write(num);
    Console.WriteLine();
}

функциональный подход...

Console.WriteLine(Enumerable
    .Range(1,100)
    .Aggregate("", 
        (a,i) => a + "\n" + (i%15==0 ? "fizzbuzz" : 
                                (i%5==0 ? "buzz" :
                                    (i%3==0 ? "fizz" : i.ToString())))));

Enumerable.Range(1, 100).ToList().ForEach(i=>Console.WriteLine($"{(i%3*i%5==0?0:i):#;}{i%3:;;Fizz}{i%5:;;Buzz}"));

в этом ответе есть все:

  • LINQ
  • Условное форматирование
  • строку интерполяции
  • все на одной строке

победа!


относительно простое решение с использованием цикла for.

нет Linq или что-то еще - просто базовая стенография, если заявления

for(int x=1;x<101;x++)
    Console.WriteLine(x%3==0?"Fizz"+(x%5==0?"Buzz":""):x%5==0?"Buzz":x+"");

решение Linq, которое очень похоже на csells (без Строковой интерполяции) и подходит для одной строки, будет:

Enumerable.Range(1,100).ToList().ForEach(x=>Console.WriteLine(x%3==0?"Fizz"+(x%5==0?"Buzz":""):x%5==0?"Buzz":x+""));

Я рекомендую использовать ++i вместо i++ в цикле for, потому что i++ требует создания копии;)

public void DoFizzBuzz()
{
    for (int i = 1; i < 101; ++i)
    {
        if (i % 15 == 0)
            Console.WriteLine ("FizzBuzz");
        else if (i % 3 == 0)
            Console.WriteLine ("Fizz");
        else if (i % 5 == 0)
            Console.WriteLine ("Buzz");
        else
            Console.WriteLine (i);
    }
}

вопрос FizzBuzz-отличный вопрос для интервью. Мы начали использовать его в процессе интервью. Это умопомрачительную сколько людей не могут решить такую простую проблему.

имейте в виду, оригинальное сообщение в блоге было в конечном итоге заблокировано из-за потока людей, публикующих больше решений. Хахаха.

независимо от того, вот мой в C++! ^_^

#include <iostream>
using namespace std;

int main(int argc, char** argv)
{
    for (int i = 1; i <= 100; ++i)
    {
        bool isMultipleOfThree = (i % 3) == 0;
        bool isMultipleOfFive = (i % 5) == 0;

        if (isMultipleOfThree) cout << "Fizz";
        if (isMultipleOfFive) cout << "Buzz";
        if (!isMultipleOfThree && !isMultipleOfFive) cout << i;

        cout << '\n';
    }

    return 0;
}

первоначальные вопросы были: 1.Как избавиться от найденного bool? 2.Есть ли лучший способ тестирования, чем foreach?

Это избавляется от bool и foreach, и я думаю, что он все еще читается.

public static void DoFizzBuzz()
{
    var combinations = new Tuple<int, string>[]  
    {  
        new Tuple<int, string> (3, "Fizz"),  
        new Tuple<int, string> (5, "Buzz"),  
    };

    for (int i = 1; i <= 100; i++)
    {
        var fb = combinations.Where(t => {
            if (i % t.Item1 == 0)
            {
                Console.Write(t.Item2);
                return true;
            }
            return false;
        }).ToList();

        if (!fb.Any())
        {
            Console.Write(i);
        }

        Console.Write(Environment.NewLine);
    }
} 

кто бы thunk мы были бы так рады простой игре детей? :)


Я бы предложил этот компактный код в качестве дополнения к предыдущим простым и приятным версиям.

for (int i = 1; i <= 100; i++) // i++ but not ++i as in your example, be careful here
{
    bool fizz = i % 3 == 0;
    bool buzz = i % 5 == 0;
    string output = fizz && buzz ? "FizzBuzz" :
                            fizz ? "Fizz" :
                            buzz ? "Buzz" :
                            i.ToString();

    Console.WriteLn(output);
}

Я новичок, вот моя попытка:

public void DoFizzBuzz()
   {
       for (int i = 1; i < 101; i++)
       {

           if ((i % 3 == 0) && (i % 5 == 0))
           {
               Console.WriteLine("{0} FizzBuzz", i);
           }
           else if (i % 3 == 0)
           {
               Console.WriteLine("{0} Fizz", i);
           }
           else if (i % 5 == 0)
           {
               Console.WriteLine("{0} Buzz", i);
           }
           else
           {
               Console.WriteLine(i);
           }

       }
       Console.ReadLine();
   }

что-то не так с моим подходом? Мой подход кажется намного проще, чем у всех остальных, поэтому он должен быть неправильным.


Вы можете использовать это и только брать сумму

static void Main(string[] args)
{
    GetFizzBuzz().Take(100).ToList().ForEach(Console.WriteLine);
}

private static IEnumerable<string> GetFizzBuzz()
{
    for (var i = 0; i < int.MaxValue; i++)
    {
        if (i % 3 == 0 && i % 5 == 0) yield return "FizzBuzz";
        if (i % 3 == 0) yield return "Fizz";
        yield return i % 5 == 0 ? "Buzz" : i.ToString(CultureInfo.InvariantCulture);
    }
}

или просто использовать это :

Enumerable.Range(1, 100).Select(s => {
    if (s % 3 == 0 && s % 5 == 0) return "FizzBuzz";
    if (s % 3 == 0) return "Fizz";
    return s%5 == 0 ? "Buzz" : s.ToString(CultureInfo.InvariantCulture);
}).ToList().ForEach(Console.WriteLine);

очевидно, что это немного выходит за рамки духа FizzBuzz challenge. Но в моем бенчмарке это было самое быстрое, что я мог сделать, пока однопоточный и все еще заканчивающийся на 100. Он полу-развернут и использует StringBuilder. Это примерно в три раза быстрее, чем стандартный подход.

const string FIZZ = " Fizz\n";
const string BUZZ = " Buzz\n";
const string FIZZBUZZ = " FizzBuzz\n";
    ...
var sb = new StringBuilder();
int i = 0;

while(true)
{       
    sb.Append(i+3);
    sb.Append(FIZZ);        
    sb.Append(i+5);
    sb.Append(BUZZ);        
    sb.Append(i+6);
    sb.Append(FIZZ);        
    sb.Append(i+9);
    sb.Append(FIZZ);        
    sb.Append(i+10);
    sb.Append(BUZZ);        
    if(i+12 > 100)
        break;
    sb.Append(i+12);
    sb.Append(FIZZ);    
    i+=15;
    sb.Append(i);
    sb.Append(FIZZBUZZ);
}

Console.Write(sb.ToString());

оператор null-coalescing действительно полезен:

string output = null;
for (int i = 1; i <= 100; i++)
{
     if (i % 3 == 0) output += "fizz";
     if (i % 5 == 0) output += "buzz";
     Console.WriteLine(output ?? i.ToString());
     output = null;
}
Console.ReadKey();

без использования кода If, c#.

 //False = 0, True = 1.
    private void DivisibilityByFiveThreeTest(int num)
    {
        string[,] values = new string [2,2]{
                             {"None","Fizz"},
                             {"Buzz","FizzBuzz"}
                             };
        for(int i=1;i< num;i++)
        Console.WriteLine(values[Convert.ToInt32(i % 5 == 0), Convert.ToInt32(i%3==0)]);

    }

Я пытался решить эту проблему, не глядя на ответы. Мне понадобилось 3 часа, чтобы добиться успеха. (Кстати, я просто программист-хобби, так что не бейте меня сильно, пожалуйста :)) Это мое решение для версии c#:

        static void Main(string[] args)
    {

        for (int i = 1; i <= 100; i++)
        {
            if(  ((i % 3) != 0) && ((i % 5) != 0))
            {
                WriteLine($"{i}");
            }
            else
            {
                if ((i % 15) == 0)
                {
                    WriteLine("FizzBuzz");
                }
                else if ((i % 3) == 0)
                {
                    WriteLine("Fizz");
                }
                else if ((i % 5) == 0)
                {
                    WriteLine("Buzz");
                }
            }                 
        }
    }

прямое решение в JavaScript

var i = 1;
while (i <= 100){
    console.log((i % 3 === 0 && i % 5 === 0) ? "FizzBuzz" : (i % 3 === 0) ? "Fizz" : (i % 5 === 0 ? "Buzz" : i));
    i++;
}

без условий if, только один тернарный оператор.

string[] s = new string[6]{"Fizz", "Buzz", "", "", "", ""};
for (int i = 1; i <= 100; i++)
{
    string output = s[(i%3)*2] + s[(i%5)+1];
    Console.WriteLine(string.IsNullOrEmpty(output)? "" + i : output);
}