Написание 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);
}
}
Итак, мои вопросы:
- Как избавиться от найденного bool?
- есть ли лучший способ проверки чем цикл 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);
}