I tried shortening Python's FizzBuzz little by little

Trigger

I was creating FizzBuzz for some reason, but suddenly I wondered, "What if I try to write FizzBuzz as short as possible?"

It may be a common article in the streets, but I will write it for my own study.

environment

Python 3.8.2

FizzBuzz rules

--Judge a number from 1 to 100 --If the number is divisible by 3, it is displayed as Fizz. --If the number is divisible by 5, it is displayed as Buzz. --Display FizzBuzz if the number is divisible by 3 and 5. --For numbers other than the above, display the number as it is (String type) --Check the result on the terminal and display each number / character string with a line break. --As much as possible according to PEP8

Part 1 (for statement)

FizzBuzz with a for statement, this is generally the case.

--Number of characters: 212 characters

for i in range(1, 101):
    if ((i % 3 == 0) & (i % 5 == 0)):
        print("FizzBuzz")
    elif (i % 5 == 0):
        print("Buzz")
    elif (i % 3 == 0):
        print("Fizz")
    else:
        print(i)

comment

Like Python, it's very easy to see.

Part 2 (while statement)

Since I wrote FizzBuzz and for statement ver. Using while statement, I also wrote while statement ver.

--Number of characters: 223 characters

i = 1
while(i < 101):
    if ((i % 3 == 0) & (i % 5 == 0)):
        print("FizzBuzz")
    elif (i % 5 == 0):
        print("Buzz")
    elif (i % 3 == 0):
        print("Fizz")
    else:
        print(i)
    i += 1

comment

The number of characters is 11 more than the for statement ver.

It's a shame, but in the case of a simple repetitive operation like the one above, the while statement seems to be slower when comparing the execution speeds of the for statement and the while statement.

-[Reference: What I did when I wanted to make Python faster> 1. Stop the while statement! !! !! ](Https://qiita.com/shaka/items/f180ae4dc945dc7b9066#1while%E6%96%87%E3%81%AF%E3%82%84%E3%82%81%E3%81%A6%E3% 81% 8A% E3% 81% 91)

The while statement is not a simple source such as FizzBuzz, but let's play an active part in another place (round throw).

Part 3 (ternary operator)

FizzBuzz using the ternary operator, I could write it in one sentence, but it was too long, so I started a new line with a colon.

--Number of characters: 126

for i in range(1, 101):
    print("FizzBuzz" if (i % 15 == 0) else "Buzz" if (i % 5 == 0) else "Fizz" if (i % 3 == 0) else i)

comment

By using the ternary operator, the expression has become much cleaner.

Let's keep it shorter and shorter with this condition.

Supplement: About the ternary operator

Fold it because it is a supplement.

The ternary operator is an operator that is often used when you want to describe a conditional branch such as an if ~ else statement in one statement.

(Value when the condition is True) if (conditions) else (conditionsがFalseのときの値)

The following if ~ else statement can be written using the ternary operator as follows.

# if~else statement
if number == 0:
    print("number is 0")
else:
    print("number is NOT 0")
#Ternary operator
print("number is 0" if number == 0 else "number is NOT 0")

Part 4 (ternary operator, generator expression)

FizzBuzz, which uses ternary operators and generator expressions, can be forced to display one line.

--Number of characters: 130 characters (Because it exceeds 80 characters, a line break is actually required)

print("\n".join("FizzBuzz" if i % 15 == 0 else "Buzz" if i % 5 == 0 else "Fizz" if i % 3 == 0 else str(i) for i in range(1, 101)))

comment

By using it in combination with the ternary operator mentioned earlier, I was able to write it neatly in one sentence.

Let's make this description even shorter next.

Supplement: Generator type

Fold it because it is a supplement.

As a rough explanation, in order to explain the generator expression, I will first explain the list comprehension notation.

  • Sorry for those who want to know the details about the generator formula, but please try google with list comprehension, generator, etc.

List comprehension

List comprehensions are Python-specific and look like this:

print([i for i in range(0,10)])  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

By using list comprehensions and the delimiter .join ([list]), you can get the result of using a normal for statement.

print("\n".join([i for i in range(0,10)]))

Based on the above, let's move on to the generator formula.

Generator type

To briefly explain, it is in [] of the list comprehension notation, and it is to create a function in parentheses and use it to perform processing.

Let's see what the generator expression returns.

print(i for i in range(0,10))  # <generator object <genexpr> at 0x000001C52B998BA0>

Since the above output result returns "something like a function that returns a list", humans cannot understand it as it is.

  • In list comprehension notation, by receiving the return value of the generator expression in the list [], the contents can be understood by humans.

However, the generator expression can also get the result of using the normal for statement by using the delimiter .join ([list]) like the list comprehension notation.

In this FizzBuzz, the number of characters is smaller when using the generator expression than the list comprehension notation, so this is adopted and described.

Part 5 (generator type, string operation, short-circuit evaluation)

FizzBuzz, which uses generators and short-circuit evaluation (some string manipulation), is much shorter.

--String: 89 characters

print("\n".join("Fizz"*(i % 3 == 0)+"Buzz"*(i % 5 == 0)or str(i) for i in range(1, 101)))

comment

It's very short, less than 100 characters.

Here is the shortest FizzBuzz I've arrived at.

However, when I looked it up, there was a shorter description of FizzBuzz (the shortest in the world), so I will introduce it next.

Supplement: String operation

Fold it because it is a supplement.

In the case of this description, in " Fizz "* (i% 3 == 0) and " Buzz "* (i% 5 == 0), use the description of character string * boolean. I did.

In Python, the bool type is a subclass of the int type, and the bool types True and False are equivalent to 0 and 1, respectively.

-Reference: issubclass (bool, int) -Reference: print (True == 1) -Reference: print (False == 0)

There is also a way to repeat a string: string * number (int).

Here, ʻABC * 3 is ʻABCABCABC, and ʻABC * 0 is an empty string "" `.

That is, if the number to be judged is a multiple of 3, boolean is true and Fizz * 1 => Fizz is displayed, and if it is a multiple of 15,"Fizz" * 1 + "Buzz" * 1 => "Fizz" + Buzz => "FizzBuzz".

Supplement: Short-circuit evaluation

Fold it because it is a supplement.

Regarding the short-circuit evaluation, the following site was very well organized (I also referred to it).

Reference: Python logical operators and, or, not (logical product, OR, negation)

Simply put, the return values of and and or follow a fixed algorithm, as shown below.

Here, the description of x (true) means that x itself is true.

    x(true) and y(false) => y
    x(false) and y(true) => x
    x(true) or y(false) => x
    x(false) or y(true) => y
    x(true) and y(true) => y
    x(false) and y(false) => x
    x(true) or y(true) => x
    x(false) or y(false) => y

By the way, if x or y is false, then:

--bool type False

  • None --Numeric values (int type and float type) 0, 0.0 --Empty string'' --Empty containers (lists, tuples, dictionaries, etc.) [], (), {},

Everything else is considered true.

In other words, in this case, in the formula (" Fizz "* (i% 3 == 0) +" Buzz "* (i% 5 == 0) or i, FizzBuzz is established by the following calculation. ..

--When the number to be judged is a multiple of 3

"Fizz"*(i % 3 == 0)+"Buzz"*(i % 5 == 0)or i => "Fizz" + "" or i => "Fizz" or i => "Fizz"

  • "Fizz" is regarded as true because "" is not empty, and "Fizz" is returned from the algorithm of x (true) or y (true) => x.

--When the number to be judged is not a multiple of 3, 5, or 15

"Fizz"*(i % 3 == 0)+"Buzz"*(i % 5 == 0)or i => "" or i => i

  • Because of "", it is regarded as false, and i is returned from the algorithm of x (false) or y (true) => y.

Part 6: World's shortest description FizzBuzz (for statement, short-circuit evaluation, bit inversion)

FizzBuzz, which is the shortest description in the world, I changed the description a little according to this rule, but it is surprisingly short!

Reference: Implement FizzBuzz in 1 byte> Python3 (59 bytes)

--Number of characters: 64 characters

for i in range(100):print(i % 3//2*"Fizz"+i % 5//4*"Buzz"or -~i)

comment

It's short. I didn't notice this statement, but it's very simple (appearingly only for and print statements).

The syntax / techniques used were for statement, short-circuit evaluation, truncation division, and bit inversion.

Supplement: Truncation division

Fold it because it is a supplement.

I was scared when I first saw it, so it's a supplement.

By setting ʻi% 3 // 2`, 0 is returned if i is 0 or 1, and 1 is returned if i is 2.

Therefore, the for statement is range (100), isn't it?

It seems that this and the short-circuit evaluation are used to shorten the entire minute.

Supplement: Bit inversion

Fold it because it is a supplement.

I was using bit inversion with the ~ operator.

In the case of Python, it seems that ~ x becomes-(x + 1) instead of simply inverting the bit.

Reference: Unary-arithmetic-and-bitwise-operations

Therefore, if you write -~ x, it will be-(-(x + 1)) , that is,(x + 1), and the range of the for statement will berange (100). It seemed to be there.

Summary

This was a good opportunity to reconfirm generator type, short circuit evaluation, bit inversion, etc.

FizzBuzz is deep!

Next time, I would like to find out if the execution speed will change if the number of characters in FizzBuzz decreases.

Recommended Posts

I tried shortening Python's FizzBuzz little by little
I tried to program bubble sort by language
I tried scraping
I tried to get an image by scraping
I tried PyQ
I tried FX technical analysis by AI "scikit-learn"
I tried AutoKeras
I tried to touch Python's GUI library "PySimple GUI"
I tried Python's "*" character output in another language
I tried papermill
I tried django-slack
I tried Django
I tried spleeter
I tried cgo
I tried to classify dragon ball by adaline
I tried increasing or decreasing the number by programming
I tried using parameterized
I tried using argparse
I tried using mimesis
I tried competitive programming
I tried running pymc
I tried ARP spoofing
I tried using aiomysql
I tried using Summpy
I tried Python> autopep8
I tried using Pipenv
I tried using matplotlib
I tried using ESPCN
I tried PyCaret2.0 (pycaret-nightly)
I tried using openpyxl
I tried deep learning
I tried AWS CDK!
I tried using Ipython
I tried to debug.
I tried using PyCaret
I tried using cron
I tried Kivy's mapview
I tried using ngrok
I tried using face_recognition
I tried to paste
I tried using Jupyter
I tried using PyCaret
I tried moving EfficientDet
I tried shell programming
I tried using Heapq
I tried using doctest
I tried Python> decorator
I tried running TensorFlow
I tried using folium
I tried using jinja2
I tried AWS Iot
I tried Bayesian optimization!
I tried using folium
I tried using time-window
I tried to implement anomaly detection by sparse structure learning
I tried to speed up video creation by parallel processing
[Introduction to simulation] I tried playing by simulating corona infection ♬
[Django] I tried to implement access control by class inheritance.
[Introduction to Pandas] I tried to increase exchange data by data interpolation ♬
I tried to classify MNIST by GNN (with PyTorch geometric)
I tried a little bit of the behavior of the zip function