【问题标题】:FizzBuzz list comprehensionFizzBu​​zz 列表理解
【发布时间】:2017-04-25 22:51:03
【问题描述】:

在学习 python 时,我一直在玩弄一些不同的 Fizz Buzz 脚本。我遇到了这个效果很好但我无法破译它是如何工作的。我知道正常的嘶嘶声如何与 for 循环和“如果 i % 3 == 0 和 i % 5 == 0”一起工作。让我难过的是 "Fizz"(not i%3) + "Buzz"(not i%5)" 有效。

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

【问题讨论】:

  • 您可以尝试在交互式 Python 会话中独立评估小型 i 的部分:"Fizz"*(not 10%3)"Buzz"*(not 5%5)
  • 在 Python 中,字符串上的 * 运算符允许将字符串“乘”以一个正整数……即指定重复该字符串的次数。所以 "somestring" * 0 表示完全不重复;用空字符串替换它。因此,这个巧妙的列表推导式根据对范围内每个数字的各种模(数学余数)运算的数值结果的布尔强制生成“Fizz”、“Buzz”、“FizzBu​​zz”字符串或整数列表1 到 100)。

标签: python fizzbuzz


【解决方案1】:
>>> 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'

您可以看到3%3 的计算结果为00 的计算结果为 False。 1 计算结果为真。

在理解中,它循环从 1 到 99 的每个数字,如果 i%3 计算结果为 Truei=3; 3%3,则打印 "Fizz" 并且对于 "Buzz" 也是如此,如果 @987654331 @。

如果"Fizz""Buzz" 均未打印,则or 之前的部分:"Fizz"*(not i%3) + "Buzz"*(not i%5) or i 计算为''+'',因此打印条件的or 部分,即i .

【讨论】:

    【解决方案2】:

    在 python 中,您可以使用乘法运算符复制字符串:

    print('aaa' * 3) # aaaaaaaaa
    

    此外,布尔值在乘法时被隐式转换为整数。因此,如果你这样做

    "Fizz"*(not i%3)
    

    首先,i%3 将返回模数的结果。然后,not 运算符会将其转换为 True(如果结果为 0),否则转换为 False(通过将其转换为布尔值然后取反)。然后应用乘法运算符,False 变为 0,True 变为 1。

    因此,如果数字可以被 3 整除,我们得到 0 作为模的结果,True 应用 not 时,1 时乘法,字符串 Fizz 复制 1 次作为结果乘法。如果它不可整除,我们得到 0 作为乘法的操作数,有效地将字符串 Fizz 复制了 0 次,因此是一个空字符串。

    Buzz 也是如此,范围内每个i 的结果只是两者的串联。

    【讨论】:

    • 谢谢你,martinarroyo,我想我知道 False 是 0,True 是 1,只是没有将它们与乘法时隐式转换为整数放在一起。感谢您写得很好。
    • 谢谢。这是一种非常巧妙的价值转换方式:D
    【解决方案3】:

    您可能知道,% 运算符返回给定除数和除数的余数。此操作仅在操作不返回余数时返回0

    例如,如果i % 3 == 0,则3i 的因子。因此i % 3 and i % 5 只会在35 可以分割i 时返回0

    因此,如果i 可以被3 整除,not i % 3 只会返回1not 语句反转输出,其中非零余数 (true) 变为 0 值 (false)。同样,零余数将成为值 1 (true)。

    "Fizz" 这样的字符串与0 相乘时,它将变成空字符串。当与1 相乘时,它将保持不变。我相信这是由于字符串的数字表示,但如果不是这种情况,有人可以纠正我。

    因此,如果i % 3 和/或i % 5 返回0 余数,则"Fizz" 和/或"Buzz" 将仅存在于该表达式的输出中。这意味着i 可以被3 和/或5 整除。

    【讨论】:

      【解决方案4】:

      列表推导表示为

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

      现在,将“源列表中的元素”部分替换为

       for i in range(1, 100)
      

      遍历包含整数 1 到 99 的列表,一次返回一个整数。

      这里是“映射表达式”

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

      它使用从“for i in range(1, 100)”返回的整数 i

      当 i 能被 3 或 5 整除时,i % 3 和 i % 5 返回 0,当 i 不能被整除时,任何其他整数都会返回。

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

      当从 (not i % 3) 或 (not i % 5) 返回的布尔值与字符串“Fizz”和“Buzz”相乘时:

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

      然后将上面返回的字符串连接起来

         "Fizz" + ""
      

      因此,“Fizz”被放置在结果列表中,并且每次迭代都会继续此过程,返回“Fizz”或“Buzz”,或者有时当字符串布尔乘法返回空字符串时乘以整数 i 本身“”。因为

           "" + "" or i    # returns i 
      

      结果列表类似于 [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBu​​zz' ......]

      注意:示例中没有使用可选的“if filter-expression”。

      【讨论】:

        【解决方案5】:

        我个人最喜欢的:

        #!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()))
        

        所有动作都在一个列表理解表达式中,其中大部分是在条件表达式中,它要么计算为一个字符串(“Fizz”,或“Buzz”或“Fizz”+“Buzz”)或一个字符串表示被评估的整数。

        这依赖于 Python 相对不寻常(甚至可能是晦涩难懂)的字符串 * 运算符......通过重复和连接来“乘”一个字符串......以及 Python 关于“真相”评估的语义。 (在 Python 空序列中:字符串、列表和元组,以及其他空容器、字典和集合,以及数值为零的值都是“假”——以及特殊的 None 和 False 个对象)。

        回到你的问题。 Python 将“将字符串乘以零”视为空字符串。它还在任何算术上下文(例如乘法)中将布尔对象视为 1 或 0。因此,如果对象可被 3 整除,则 not i%3 的布尔值是 True ...即模 3 运算返回非零值。因此,这些字符串中的每一个都“乘”以一或零(相当于调用 int(not(bool(i%X))) ...其中 X 在一个子表达式中为 3,在子表达式中为 5另一个。(注意:not 是一元运算符,而不是函数;但它可以写成函数调用,因为 not(x) 的计算结果与 not x ...在大多数情况下,多余的括号是无害的)。

        我更喜欢返回(或产生)整数的字符串转换,因为您可以在其他函数中以自然的方式使用此表达式的结果(例如,在调用 string.join( ) 方法)。

        【讨论】:

          【解决方案6】:

          你可以使用:

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

          希望这一切都解决了。

          【讨论】:

          • 您也可以将 i%15 == 0 用于“FizzBu​​zz”:)
          【解决方案7】:

          试试这样的:

          def fizz_buzz(upper):
              up_limit = upper +1
              fbl = ['fb' if i%15 == 0  #fizzbuzz if divisible by both
                 else 'f' if i%3 == 0   #fizz if divisible by 3
                 else 'b' if i%5 == 0   #buzz if divisible by 5
                 else i                 #else present number
                 for i in range(1,up_limit)]
              return fbl
          

          【讨论】:

            【解决方案8】:

            我认为以下方法有助于我理解列表理解结构。

            def fizzBuzz(upper_limit):
            
              def mapper(a):
                result = ''
                if a % 3 == 0:
                  result = result + 'Fizz'
                if a % 5 == 0:
                  result = result + 'Buzz' 
                return result
            
              return [mapper(x) if mapper(x) else x for x in range(1,upper_limit+1)]
            
            fizzBuzz(16)
            [1,2,'Fizz',4,'Buzz','Fizz',7,8,'Fizz','Buzz', 11,'Fizz',13,14,'FizzBuzz',16]
            

            【讨论】:

              猜你喜欢
              • 2012-02-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-18
              • 2012-11-04
              • 1970-01-01
              • 1970-01-01
              • 2016-01-15
              相关资源
              最近更新 更多