FizzBuzz list comprehension

时光毁灭记忆、已成空白 提交于 2019-12-24 05:56:08

问题


I was messing around with some different fizz buzz scripts as I learn python. I came across this one which works great but I can't decipher how it works. I know how the normal fizz buzz works with a for loop and "if i % 3 == 0 and i % 5 == 0". What has me stumped is how "Fizz"(not i%3) + "Buzz"(not i%5)" works.

x = ["Fizz"*(not i%3) + "Buzz"*(not i%5) or i for i in range(1, 100)]

回答1:


In python you can replicate a string by using the multiplication operator:

print('aaa' * 3) # aaaaaaaaa

Also, boolean values are implicitly casted to integers on multiplication. Thus, if you do

"Fizz"*(not i%3)

First, the i%3 will return the result of the modulo. Then, the not operator will convert it to either True if the result was 0, or to False otherwise (by casting it to boolean and then negating the value). By then applying a multiplication operator, False turns to 0 and True turns into 1.

Thus, if the number is divisible by 3, we get 0 as the result of the modulo, True when applying not, 1 when multiplying, and the string Fizz replicated 1 time as the result of the multiplication. If it is not divisible, we get 0 as operand for the multiplication, effectively getting the string Fizz replicated 0 times, thus an empty string.

The same goes for Buzz, and the result for each i in the range is just the concatenation of the two.




回答2:


List comprehension is expressed as

  L = [mapping-expression for element in source-list if filter-expression]

now, replace "for element in source-list" part with

 for i in range(1, 100)

which iterates over a list of containing integers 1 to 99 returning one integer at a time.

"mapping-expression" here is

 "Fizz"*(not i%3) + "Buzz"*(not i%5) or i

which uses the integer i returned from "for i in range(1, 100)"

when i is divisible by 3 or 5, i % 3 and i % 5 returns 0, any other integer retuned when i is not divisible.

  (not i % 3) # return True when i is divisible by 3
  (not i % 5) # returns False when i is not divisible by 5

when the booleans returned from (not i % 3) or (not i % 5) is multiplied with strings "Fizz" and "Buzz":

  "Fizz" * True   # returns "Fizz"
  "Buzz" * False   # returns ""

then the Strings returned above are concatenated

   "Fizz" + ""

as a result "Fizz" is placed in the resulting list and this process goes on for each iteration, returning either "Fizz" or "Buzz" or sometimes times the integer i itself when both the string boolean multiplication returns a empty string "". since

     "" + "" or i    # returns i 

The resulting list is something like [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz' ......]

note : the optional "if filter-expression" is not used in the example.




回答3:


You can use:

["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 x] 

Hope this clears.




回答4:


>>> 3%3
0
>>> not 3%3
True
>>> 
>>> 3%2
1
>>> not 3%2
False
>>> 
>>> if 0:
...   print 'true'
... 
>>> if 1:
...   print 'true'
... 
true
>>> False * 'Fizz'
''
>>> True * 'Fizz'
'Fizz'

You can see that 3%3 evaluates to 0 and 0 evaluates to False. 1 evaluates to true.

In the comprehension, it loops for every number from 1 to 99, and if i%3 evaluates to True or i=3; 3%3, then "Fizz" is printed and the same is true for "Buzz" if i%5 == 0.

If neither "Fizz" nor "Buzz" get printed, the part before the or here: "Fizz"*(not i%3) + "Buzz"*(not i%5) or i evaluates to ''+'' so the or part of the condition is printed, which is just i.




回答5:


As you may know, the % operator returns the remainder of a given dividend and divisor. This operation only returns 0 when the operation returns no remainder.

For example, if i % 3 == 0, then 3 is a factor of i. Therefore i % 3 and i % 5 will only return 0 when 3 or 5 can divide i.

Thus not i % 3 will only return 1 if i is divisible by 3. The not statement inverts the output, where a nonzero remainder (true) becomes the 0 value (false). Likewise, a zero remainder will become the value 1 (true).

When a string like "Fizz" is multiplied with a 0, it will become the empty string. When multiplied with a 1, it will remain the same. I believe this is due to the numerical representation of strings but someone can correct me if this is not the case.

Therefore, "Fizz" and/or "Buzz" will only exist in the output of that expression if i % 3 and/or i % 5 return 0 remainders. Meaning that i is divisible by 3 and/or 5.




回答6:


My personal favorite:

#!python
from __future__ import print_function
def fizz_buzz(lower=1, upper=101):
    return ["Fizz"*(x % 3 == 0) + "Buzz"*(x % 5 == 0) or str(x) \
       for x in range(lower, upper)]

print('\n'.join(fizz_buzz()))

All the action is in a list comprehension expression and most of that is in conditional expression which either evaluates into a string ("Fizz", or "Buzz" or "Fizz"+"Buzz") or into a string representation of the integer being evaluated.

This relies on Python's relatively unusual (perhaps even obscure) * operator for strings ... to "multiply" a string via duplications and concatenation ... and also on Python's semantics regarding evaluation of "truth." (In Python empty sequences: strings, lists, and tuples, as well as other empty containers, dictionaries and sets, and numerically zero values are all "false" --- along with the special None and False objects).

Back to your question. Python treats "multiplying a string by zero" as an empty string. It also treats a Boolean object as 1 or 0 in any arithmetic context (such as multiplication). Thus the Boolean of not i%3 is True if the object is divisible by 3 ... that is the modulo 3 operation returns a non-zero value. So each of these strings is "multiplied" by one or zero (the equivalent of calling int(not(bool(i%X))) ... where X is 3 in one subexpression and 5 in the other. (Note: not is a unary operator, not a function; but it can be written like a function call because not(x) evaluates the same as not x ... the extraneous parentheses are harmless in most cases).

I prefer returning (or yielding) the string conversion of the integer precisely because you can then uses the results from this expression in other functions in a natural way (for example when calling the string.join() method).



来源:https://stackoverflow.com/questions/41077697/fizzbuzz-list-comprehension

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!