【问题标题】:Append a list to a list将列表附加到列表
【发布时间】:2016-04-13 19:26:10
【问题描述】:

我有一个数字列表,我想将 N 个元素提取为列表,并将它们存储在另一个列表中。 示例:

list1 = [1,2,3,4,5,6,7,8,9]
resultList = [[1,2,3],[4,5,6],[7,8,9]]

我已经完成了以下操作

def getLines(square, N):
    i = 0

    line  = [None]*N
    lines = list()

    for elt in square:
        line[i] = elt
        i += 1
        if i == N:
            lines.append(line)
            i = 0

return lines

为什么我总是3次得到最后一个列表

[[7,8,9],[7,8,9],[7,8,9]]

当我调用函数getLines(list1, 3)

我也试过去掉临时列表,直接将元素添加到resultList,如下所示:

def getLines(square, N):
    i = 0
    j = 0
    lines = [[None]*N]*N # Need to be initialized to be able to index it.

    for elt in square:
        lines[i][j] = elt
        j += 1
        if j == N:
            i += 1
            j = 0

return lines

最后一组仍然出现 N 次。有关如何解决此问题的任何提示?

【问题讨论】:

    标签: list python-3.x append


    【解决方案1】:

    这是因为您只创建了一个内部列表对象并对其进行了更改。
    在伪代码中,您正在做的是:

    • 创建一个名为line 的列表,并为其分配[None, None, None]
    • 创建一个名为lines的空列表
    • 三回:
      -- 从square 列表中选择 n 个项目
      -- 将这三个项目分配给line[0]line[1]line[2]
      -- 将line 附加到lines

    所以,您正在做的是分配给line个别项目。这很重要 - 您不是每次都创建一个新对象,而是更改 line 列表中的各个项目。
    最后,line 将指向列表[7, 8, 9]。您可以看到lines 实质上是[line, line, line](相同对象的三倍的列表),所以现在它具体指向[[7,8,9], [7,8,9], [7,8,9]]

    要解决这个问题,最能保留原始代码的解决方案可能是在添加 line 后重新定义它。这样,变量名line 每次都会引用不同的列表,就不会有这个问题了。

    def getLines(square, N):
        i = 0
    
        line  = [None]*N
        lines = list()
    
        for elt in square:
            line[i] = elt
            i += 1
            if i == N:
                lines.append(line)
                line  = [None]*N # Now `line` points to a different object
                i = 0
    
        return lines
    

    当然,有更精简、更 Pythonic 的代码可以做同样的事情(我看到已经给出了答案)。

    编辑 - 好的,这里有一个更详细的解释。
    也许其中一个关键概念是列表不是其他对象的容器。它们仅包含对其他对象的引用。
    另一个关键概念是,当您更改列表中的项目(项目分配)时,您不会使整个列表对象成为另一个对象。您只是在更改其中的引用。这是我们在很多情况下认为理所当然的事情,但是当我们希望事情朝着相反的方向发展并“回收”一个列表时,不知何故变得违反直觉。

    正如我在 cmets 中所写的那样,如果 list 是一只名为 Fluffy 的猫,那么每次添加时都会创建一个指向 Fluffy 的镜像。所以你可以给 Fluffy 戴一顶派对帽,放一面镜子指向它,然后给 Fluffy 一个小丑鼻子,戴上另一面镜子,然后把 Fluffy 打扮成芭蕾舞演员,再加上第三面镜子,当你照镜子时,所有其中三个将展示芭蕾舞演员蓬松。 (对不起蓬松)。

    我的意思是,实际上在您的第一个脚本中,当您执行附加操作时:

        lines.append(line)  
    

    根据我提到的第一个概念,您没有将lines 包含 line 的当前状态作为一个单独的对象。您正在附加对line 列表的引用。

    当你这样做时,

        line[i] = elt
    

    根据第二个概念,当然line 总是同一个对象;您只是在更改在 i-th 位置引用的内容。

    这就是为什么在您的脚本末尾,lines 会显示为“包含三个相同的对象”:因为您实际上将三个引用附加到同一个对象。当您要求查看lists 的内容时,您将阅读三遍list 对象的当前状态。

    在我上面提供的代码中,我重新定义了名称 lists 以使其在每次附加到 lists 时引用一个全新列表:

            lines.append(line)  
            line  = [None]*N # Now `line` points to a different object  
    

    这样,在脚本的末尾我附加了“三只不同的猫”,每只都方便地命名为 Fluffy,直到我添加它,以便为之后的新 Fluffy 列表留出空间。

    现在,在您的第二个脚本中,您执行类似的操作。关键指令是:

        lines = [[None]*N]*N # Need to be initialized to be able to index it.
    

    在这一行中,您正在创建两个对象:
    - 列表[None, None, None]
    - 名为lines 的列表,其中包含对同一列表[None, None, None] 的N 个引用。

    你所做的只是直接创造出 Fluffy 和指向他的三面镜子。
    事实上,如果您更改 lines[0][2]lines[1][2],您只是更改了同一个 Fluffy 的同一个项目 [2]。

    你真正想做的是,

        lines = [[None]*N for i in range(N)]  
    

    它创建了三只不同的猫——我的意思是,列出并让lines 指向这三只。

    【讨论】:

    • 感谢您的解释。但是为什么“行”只附加最后一个“行”?我每次都在更改“行”,不应该每次都附加(在if语句中)吗?
    • @Ouss4 这不是你应该看到的方式。在命名对象和单独分配给对象中的项目之间存在关键区别(这将是您通过解决此问题学到的具体内容)。
    • @Ouss4 试着这样看待它:我有一只猫叫 Fluffy。 (1) 我会给它戴上绿帽子。我会在 Fluffy 有一个镜像点。 (2) 现在我要给它戴上小丑帽。我将在 Fluffy 设置第二个镜像点。 (3) 现在我要把它打扮得像个芭蕾舞演员。我将在 Fluffy 设置第三个镜像点。 (4) 奇怪的是,所有三个镜子都显示了现在穿着芭蕾舞演员的蓬松。 ......所以为了让它工作,你需要使用三只猫(三个不同的物体)而不是改变同一只猫的帽子。
    • 抱歉,我们如何对我给出的第二个代码 sn-p 应用相同的推理?它不应该改变“行”的每个值吗?
    • 看起来,Fluffy 正对着一面镜子,并透过这面镜子看后面的另一面镜子。 (好吧,我得到 [[...]],一些谷歌搜索表明它表示带有省略号的无限数据结构。准确吗?)编辑:看起来我们有一些解释 here
    【解决方案2】:

    你可以考虑这样解决这个问题:

    def getLines(square, N):
        return [square[i:i + N] for i in range(0, len(square), N)]
    

    例如:getLines([1, 2, 3, 4, 5, 6, 7, 8, 9], 3) 将返回[[1, 2, 3], [4, 5, 6], [7, 8, 9]],或getLines([1, 2, 3, 4, 5, 6, 7, 8, 9], 2) 结果为[[1, 2], [3, 4], [5, 6], [7, 8], [9]],等等。

    【讨论】:

    • 真是太好了,谢谢。我本来打算用列表理解来做的,但在试图解决最后一个问题时被抓住了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2014-02-14
    • 2015-08-05
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多