JavaScript — Как решить задачу FizzBuzz
-
Если кто не в курсе — это такая штука, которую дают на собеседованиях, чтобы проверить, умеешь ли ты вообще хоть что-то писать на JavaScript. Ну или просто чтобы посмеяться над твоим кодом
.
Что такое FizzBuzz?
Для тех, кто в танке: FizzBuzz — это задача, где тебе нужно вывести числа от 1 до N (например, до 100), но с некоторыми условиями:
- Если число делится на 3, то вместо него выводится слово “Fizz”.
- Если число делится на 5, то выводится “Buzz”.
- Если число делится и на 3, и на 5, то выводится “FizzBuzz”.
- Если ни одно из условий не выполняется, просто выводится само число.
Звучит просто, правда? Но, сколько же можно усложнять эту задачу! Давайте разберемся, как я это делал, и какие варианты решения у меня получились.
Первый подход: Просто работаем
Начнем с самого простого и прямолинейного решения. Тупо цикл
for
, проверки черезif
и вывод в консоль. Вот такой код у меня получился:for (let i = 1; i <= 100; i++) { if (i % 3 === 0 && i % 5 === 0) { console.log("FizzBuzz"); } else if (i % 3 === 0) { console.log("Fizz"); } else if (i % 5 === 0) { console.log("Buzz"); } else { console.log(i); } }
Вроде бы всё работает, но, этот код выглядит как будто его написал первокурсник. Можно ли сделать лучше? Конечно, можно!
Второй подход: Улучшаем читаемость
Я подумал: а почему бы не использовать тернарный оператор? Это же модно, молодёжно и компактно! Вот что у меня вышло:
for (let i = 1; i <= 100; i++) { console.log( i % 15 === 0 ? "FizzBuzz" : i % 3 === 0 ? "Fizz" : i % 5 === 0 ? "Buzz" : i ); }
Круто, правда? Но знаете что? Этот код всё равно выглядит как ебучий костыль. Да, он короче, но понятнее ли он стал? Не уверен. Может, есть способ ещё круче?
Третий подход: Функциональный стиль
А что, если мы попробуем написать более функционально? Создадим функцию, которая будет принимать число и возвращать нужную строку. Вот так:
const fizzBuzz = (num) => { let output = ""; if (num % 3 === 0) output += "Fizz"; if (num % 5 === 0) output += "Buzz"; return output || num; }; for (let i = 1; i <= 100; i++) { console.log(fizzBuzz(i)); }
Теперь всё выглядит намного чище! Мы вынесли логику в отдельную функцию, и основной цикл стал проще. Но знаете что? Я всё равно чувствую, что можно ещё больше поиздеваться над этой задачей.
Четвертый подход: Array и map 🤯
А давайте сделаем это через массивы и метод
map
! Звучит как извращение, но почему бы и нет? Вот что у меня получилось:const result = Array.from({ length: 100 }, (_, i) => { const num = i + 1; return num % 15 === 0 ? "FizzBuzz" : num % 3 === 0 ? "Fizz" : num % 5 === 0 ? "Buzz" : num; }); console.log(result.join("\n"));
Теперь мы создаем массив длиной 100, заполняем его значениями через
map
, а потом выводим всё одной строкой черезjoin
. Красота! Но, бля, зачем я это делаю? Это же FizzBuzz, а не какой-нибудь ML-проект!
Пятый подход: Генераторы и yield
А что, если мы добавим генераторы? Зачем? Просто потому что можем! Вот это чудовище:
function* fizzBuzzGenerator(limit) { for (let i = 1; i <= limit; i++) { yield i % 15 === 0 ? "FizzBuzz" : i % 3 === 0 ? "Fizz" : i % 5 === 0 ? "Buzz" : i; } } const generator = fizzBuzzGenerator(100); for (const value of generator) { console.log(value); }
Генераторы — это, конечно, мощная штука, но для FizzBuzz это явно overengineering. Хотя, знаете что? Мне нравится!
Вот такие вот пироги, ребята. FizzBuzz — это, конечно задачка для новичков, сколько же можно её усложнять? Я даже не знаю, какой вариант выбрать. Может, просто оставить первый, чтобы не выглядеть как долбоёб на собеседовании?