Пришло время оживить преданный забвению FizzBuzz. Попробуем найти самое компактное решение FizzBuzz на Python.
Условие задачи
Напишите программу, печатающую числа от 1 до 100. Вместо чисел кратных трём, программа должна печатать 'Fizz'. Вместо чисел кратных пяти - 'Buzz'. Если число кратно и трём, и пяти, программа должна печатать 'FizzBuzz'.
Основа
Начнём со стандартного, классического решения:
for i in range(1, 101):
if i%3==0 and i%5==0:
print('FizzBuzz')
elif i%3==0:
print('Fizz')
elif i%5==0:
print('Buzz')
else:
print(i)
Укладываем стандартное решение в стандартный однострочник
print('\n'.join('FizzBuzz' if i%3==0 and i%5==0 else 'Fizz' if i%3==0 else 'Buzz' if i%5==0 else str(i) for i in range(1, 101)))
Избавляемся от Join, приручаем Print
[print('FizzBuzz' if i%3==0 and i%5==0 else 'Fizz' if i%3==0 else 'Buzz' if i%5==0 else i) for i in range(1, 101)]
Добавляем срез, укрощаем if else
[print('FizzBuzz'[4 if i%3 else 0:4 if i%5 else 8] or i) for i in range(1, 101)]
Оптимизируем срез, избавляемся от if else
[print('FizzBuzz'[i*i%3*4:8--i**4%5] or i) for i in range(1, 101)]
Сократили неплохо. Но, похоже с этой вариацией дальше не продвинуться. Пробуем иной вариант.
Заменяем срез конкатенацией, вертаем оператор modulo
[print('Fizz'*(i%3==0)+'Buzz'*(i%5==0) or i) for i in range(1, 101)]
Оптимизируем решение. Выравниваем по длине со срезом
[print((i%3<1)*'Fizz'+(i%5<1)*'Buzz' or i) for i in range(1, 101)]
Уходим в отрыв. Модифицируем окончательный вариант
[print(i%3//2*'Fizz'+i%5//4*'Buzz' or i+1) for i in range(100)]
А что по скорости?
print('\n'.join('FizzBuzz' if i%3==0 and i%5==0 else 'Fizz' if i%3==0 else 'Buzz' if i%5==0 else str(i) for i in range(1, 101))) # 2.53 msec
[print('FizzBuzz' if i%3==0 and i%5==0 else 'Fizz' if i%3==0 else 'Buzz' if i%5==0 else i) for i in range(1, 101)] # 8.11 msec
[print('FizzBuzz'[4 if i%3 else 0:4 if i%5 else 8] or i) for i in range(1, 101)] # 8.43 msec
[print('FizzBuzz'[i*i%3*4:8--i**4%5] or i) for i in range(1, 101)] # 8.31 msec
[print('Fizz'*(i%3==0)+'Buzz'*(i%5==0) or i) for i in range(1, 101)] # 8.38 msec
[print((i%3<1)*'Fizz'+(i%5<1)*'Buzz' or i) for i in range(1, 101)] # 8.4 msec
[print(i%3//2*'Fizz'+i%5//4*'Buzz' or i+1) for i in range(100)] # 8.49 msec
Методика расчёта: python -m timeit "выражение"
Вместо заключения
Помимо этой статьи, на Хабре мною опубликованы ещё пара статей на тему Python однострочников. Если интересно, ознакомиться можно по ссылкам ниже:
Всем спасибо.
Комментарии (5)
lavagod
05.12.2021 21:21+7Самое компактное решение не есть самое быстрое, имхо. Вот, например, вам решение тоже в одну строку. Не знаю как там по времени, но наверно тоже будет быстро:)
print("1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz")
SamXYZ
Интересные способы решения,