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.
Python 3.8.2
--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
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)
Like Python, it's very easy to see.
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
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).
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)
By using the ternary operator, the expression has become much cleaner.
Let's keep it shorter and shorter with this condition.
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")
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)))
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.
As a rough explanation, in order to explain the generator expression, I will first explain the list comprehension notation.
list comprehension
, generator
, etc.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.
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.
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.
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)))
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.
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"
.
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
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"
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
x (false) or y (true) => y
.FizzBuzz, which is the shortest description in the world, I changed the description a little according to this rule, but it is surprisingly short!
--Number of characters: 64 characters
for i in range(100):print(i % 3//2*"Fizz"+i % 5//4*"Buzz"or -~i)
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.
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.
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.
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.
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