将列表附加到列表中

时间:2016-04-13 19:26:10

标签: list python-3.x append

我有一个数字列表,我想将 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

为什么我总是三次获得最后一个列表

[[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 次。关于如何解决这个问题的任何提示?

2 个答案:

答案 0 :(得分:1)

您可以考虑解决此问题:

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]],依此类推。

答案 1 :(得分: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的代码可以做同样的事情(我看到已经给出了答案)。

编辑 - 好的,这里有更详细的解释。
也许其中一个关键概念是列表不是其他对象的容器;他们只是提到其他对象 另一个关键概念是,当您更改列表中的项目(项目分配)时,您不会使整个列表对象成为另一个对象。您只是在其中更改引用。这是我们在很多情况下给予的理所当然的事情,但是当我们希望事情走向另一条路并且回收"时,某种程度上会变得违反直觉。一个列表。

正如我在评论中写的那样,如果list是一只名为蓬松的猫,那么每次你追加你的时候都会创建一个指向Fluffy的镜像。所以你可以穿上蓬松的派对帽,戴上一面指向它的镜子,然后给蓬松一个小丑鼻子,戴上另一面镜子,然后穿蓬蓬作为芭蕾舞女演员,加上第三面镜子,当你看镜子时,所有其中三人将展示芭蕾舞女演员蓬松。 (抱歉蓬松)。

我的意思是,在您的第一个脚本中练习,当您执行追加时:

    lines.append(line)  

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

当你这样做时,

    line[i] = elt

第二个概念,当然line始终是同一个对象;你只是改变 i-th 位置引用的内容。

这就是为什么在脚本结束时,lines将出现在"包含三个相同的对象":因为您实际上将三个引用附加到同一个对象。当您要求查看lists的内容时,您将读取三次list对象的当前状态。

在我上面提供的代码中,我重新定义了名称lists,以便在每次将{em>全新列表附加到{{1}时}:

lists

这样,在脚本的最后我有三只不同的猫"附上,每一个都被方便地命名为Fluffy,直到我附加它,之后为新的Fluffy列表留出空间。

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

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

在这一行中,您将创建两个对象:
  - 列表 lines = [[None]*N]*N # Need to be initialized to be able to index it.
  - 名为[None, None, None]的列表,其中包含对同一列表lines的N个引用。

你做的只是直接创造蓬松和三个镜子指向他 事实上,如果您更改[None, None, None]lines[0][2],则只需更改同一个Fluffy的相同项目[2]即可。

你真正想做的是,

lines[1][2]

创建了三只不同的猫 - 我的意思是,列表, lines = [[None]*N for i in range(N)] 指向三只猫。