【问题标题】:Explanation of how nested list comprehension works?解释嵌套列表理解如何工作?
【发布时间】:2014-01-05 12:17:06
【问题描述】:

我没有问题理解这一点:

a = [1,2,3,4]
b = [x for x in a]

我以为就是这样,但后来我发现了这个sn-p:

a = [[1,2],[3,4],[5,6]]
b = [x for xs in a for x in xs]

这使得b = [1,2,3,4,5,6]。问题是我无法理解[x for xs in a for x in xs] 中的语法,有人能解释一下它是如何工作的吗?

【问题讨论】:

    标签: python list


    【解决方案1】:

    由于第一个变量和错误的命名约定,导致这种语法的整个混乱。

    [door for room in house for door in room]
    

    这里的“门”是造成混乱的原因

    想象一下,如果一开始没有“门”变量

    [for room in house for door in room]
    

    这样我们可以做得更好。

    而使用 [x, xs, y] 之类的变量会变得更加混乱,所以变量命名也是一个关键

    你也可以对循环变量做一些事情,比如:

    doors = [door for room in house for door in str(room)]
    

    相当于:

    for room in house:
        for door in str(room):
            bolts.append(door)
    

    【讨论】:

      【解决方案2】:

      英语语法:

      b = "a list of 'specific items' taken from 'what loop?' "
      b = [x for xs in a for x in xs]
      

      x 是具体项目
      for xs in a for x in xs 是循环

      【讨论】:

        【解决方案3】:

        您要求的是嵌套列表。

        让我尝试逐步回答这个问题,涵盖以下主题:

        • For 循环
        • 列表推导
        • 嵌套 for 循环和列表推导

        For 循环

        您有这个列表:lst = [0,1,2,3,4,5,6,7,8],并且您想一次迭代列表一项并将它们添加到新列表中。你做一个简单的 for 循环:

        lst = [0,1,2,3,4,5,6,7,8]
        new_list = []
        
        for lst_item in lst:
            new_list.append(lst_item)
        

        你可以用列表推导做同样的事情(它更 Pythonic)。

        列表理解

        列表推导是一种(*有时)更简单、更优雅的创建列表的方式。

        new_list = [lst_item for lst_item in lst]
        

        你这样读:对于lst中的每个lst_item,将lst_item添加到new_list

        嵌套列表

        什么是嵌套列表? 一个简单的定义:它是一个包含子列表的列表。您在另一个列表中有列表。

        *根据您与谁交谈,嵌套列表是列表推导式比常规 for 循环更难阅读的情况之一。

        假设您有这个嵌套列表:nested_list = [[0,1,2], [3,4,5], [6,7,8]],并且您想将其转换为类似这样的扁平列表:flattened list = [0,1,2,3,4,5,6,7,8]

        如果您使用与以前相同的 for 循环,您将无法获得它。

        flattened_list = []
        for list_item in nested_list:
            flattened_list.append(list_item)
        

        为什么? 因为每个list_item 实际上都是子列表之一。在第一次迭代中,你得到[0,1,2],然后是[3,4,5],最后是[6,7,8]

        你可以这样检查:

        nested_list[0] == [0, 1, 2]
        nested_list[1] == [3, 4, 5]
        nested_list[2] == [6, 7, 8]
        

        您需要一种方法进入子列表并将每个子列表项添加到flattened list

        How? 你增加了一层额外的迭代。实际上,您为每一层子列表添加一个。

        在上面的示例中,您有两个层。

        for 循环解决方案。

        nested_list = [[0,1,2], [3,4,5], [6,7,8]]
        
        flattened_list = []
        for sublist in nested_list:
            for item in sublist:
                flattened_list.append(item)
        

        让我们大声朗读这段代码。

        for sublist in nested_list: 每个子列表是[0,1,2][3,4,5][6,7,8]。在第一个循环的第一次迭代中,我们进入[0,1,2]

        for item in sublist:[0,1,2]的第一项是0,它附加在flattened_list之后。然后是1,最后是2

        到目前为止,flattened_list[0,1,2]

        我们完成了第二个循环的最后一次迭代,所以我们进入第一个循环的下一次迭代。我们进去[3,4,5]

        然后我们转到此子列表的每个项目并将其附加到flattened_list。然后我们进行下一次迭代,依此类推。

        如何使用列表理解来做到这一点?

        列表理解解决方案。

        flattened_list = [item for sublist in nested_list for item in sublist]
        

        你是这样读的:从nested_list 的每个sublist 中添加每个item

        它更简洁,但如果你有很多层,它可能会变得更难阅读。

        让我们一起看看

        #for loop
        nested_list = [[0,1,2], [3,4,5], [6,7,8]]
        
        flattened_list = []
        for sublist in nested_list:
            for item in sublist:
                flattened_list.append(item)
        
        ----------------------------------------------------------------------
        
        #list comprehension
        flattened_list = [item for sublist in nested_list for item in sublist]
        

        您将添加更多的迭代层for x in y


        2021 年 4 月编辑。

        您可以使用 Numpy 展平嵌套列表。从技术上讲,在 Numpy 中,该术语将是 'array'。

        对于一个小列表来说,这是一个矫枉过正,但如果你在一个列表中处理数百万个数字,你可能需要 Numpy。

        来自 Numpy 的 documentation。我们有一个attributeflat

        b = np.array(
        [
          [ 0,  1,  2,  3],
          [10, 11, 12, 13],
          [20, 21, 22, 23],
          [30, 31, 32, 33],
          [40, 41, 42, 43]
        ]
        )
        
        for element in b.flat:
            print(element)
        
        0
        1
        2
        ...
        41
        42
        43
        

        【讨论】:

          【解决方案4】:

          这是我记忆最深刻的方式: (伪代码,但有这种模式)

          [(x,y,z) (loop 1) (loop 2) (loop 3)]
          

          最右边的循环(循环 3)是最内层的循环。

          [(x,y,z)    for x in range(3)    for y in range(3)    for z in range(3)]
          

          结构如下:

          for x in range(3):
              for y in range(3):
                  for z in range(3):
                      print((x,y,z))
          

          编辑我想添加另一个模式:

          [(result) (loop 1) (loop 2) (loop 3) (condition)]
          

          例如:

          [(x,y,z)    for x in range(3)    for y in range(3)    for z in range(3)    if x == y == z]
          

          有这种类型的结构:

          for x in range(3):
              for y in range(3):
                  for z in range(3):
                      if x == y == z:
                          print((x,y,z))
          
          
          
          

          【讨论】:

            【解决方案5】:

            是的,您可以在列表解析内嵌套 for 循环。您甚至可以在其中嵌套 if 语句。

            dice_rolls = []
            for roll1 in range(1,7):
                for roll2 in range(1,7):
                    for roll3 in range(1,7):
                        dice_rolls.append((roll1, roll2, roll3))
            
            # becomes
            
            dice_rolls = [(roll1, roll2, roll3) for roll1 in range(1, 7) for roll2 in range(1, 7) 
                          for roll3 in range(1, 7)]
            

            我写了a short article on medium 解释了列表推导和其他一些你可以用 python 做的很酷的事情,如果你有兴趣可以看看:)

            【讨论】:

              【解决方案6】:

              这是一个嵌套推导的例子。将a = [[1,2],[3,4],[5,6]] 视为一个 3 x 2 矩阵(matrix= [[1,2],[3,4],[5,6]])。

                     ______
              row 1 |1 | 2 |
                     ______
              row 2 |3 | 4 |
                     ______
              row 3 |5 | 6 |
                     ______
              

              您看到的列表推导是将矩阵中的所有元素放入列表的另一种方法。

              我将尝试使用不同的变量来解释这一点,希望更有意义。

              b = [element for row in matrix for element in row]
              

              第一个 for 循环遍历矩阵内的行,即[1,2],[3,4],[5,6]。第二个 for 循环遍历 2 个元素列表中的每个元素。

              我在我的网站http://programmathics.com/programming/python/python-list-comprehension-tutorial/ 上写了一篇关于列表理解的小文章,它实际上涵盖了与这个问题非常相似的场景。我还给出了一些关于 python 列表理解的其他示例和解释。

              免责声明:我是该网站的创建者。

              【讨论】:

                【解决方案7】:

                啊,难以理解的“嵌套”理解。循环的展开顺序与理解中的顺序相同。

                [leaf for branch in tree for leaf in branch]
                

                这样想会有所帮助。

                for branch in tree:
                    for leaf in branch:
                        yield leaf
                

                PEP202 断言这种语法“最后一个变化最快的索引”是“正确的”,特别是没有解释为什么

                【讨论】:

                • 对于它的价值,你不认为[leaf for leaf in branch for branch in tree] 更易于阅读吗?希望这能以另一种方式工作。
                • 也许它需要知道branchleaf 之前存在?从左到右阅读理解。
                • @Ray 确实如此,但这似乎是一种随意的必要性。仅仅因为 Python 目前需要从左到右读取它并不意味着它不能更改为从右到左读取以提高可读性。
                • 我很难进一步概括这一点。具体来说,如何将其扩展到 n 维列表?离开这里的例子,我终于弄清楚了 n = 3 的情况:[leaf for tree in forest for branch in tree for leaf in branch] 回想起来很简单。
                • 感谢@Greenstick,n 维实际上使这更容易理解。 [atom for galaxy in universe for star_system in galaxy for planet in star_system for continent in planet for ecosystem in continent for forest in ecosystem for tree in forest for branch in tree for leaf in branch for vein in leaf for fibre in vein for cell in fibre for molecule in cell for atom in molecule]
                【解决方案8】:

                如果a = [[1,2],[3,4],[5,6]],那么如果我们展开该列表组合,我们会得到:

                      +----------------a------------------+ 
                      | +--xs---+ , +--xs---+ , +--xs---+ | for xs in a
                      | | x , x |   | x , x |   | x , x | | for x in xs
                a  =  [ [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 ] ]
                b  =  [ x for xs in a for x in xs ] == [1,2,3,4,5,6] #a list of just the "x"s
                

                【讨论】:

                  【解决方案9】:

                  可以这样写

                  result = []
                  for xs in a:
                      for x in xs:
                          result.append(x)
                  

                  您可以阅读更多关于它的信息here

                  【讨论】:

                    【解决方案10】:

                    有效地:

                    ...for xs in a...]
                    

                    正在遍历您的主(外部)列表并依次返回您的每个子列表。

                    ...for x in xs]
                    

                    然后遍历这些子列表中的每一个。

                    这可以重写为:

                    b = []
                    for xs in a:
                        for x in xs:
                            b.append(x)
                    

                    【讨论】:

                      【解决方案11】:

                      b = [x for xs in a for x in xs] 类似于下面的嵌套循环。

                      b = []
                      for xs in a:
                         for x in xs:
                             b.append(x)
                      

                      【讨论】:

                        猜你喜欢
                        • 2020-05-15
                        • 2011-12-24
                        • 2019-08-30
                        • 1970-01-01
                        • 2019-08-20
                        • 2020-05-29
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多