我有一个数字列表,我想将 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 次。关于如何解决这个问题的任何提示?
答案 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)]
指向三只猫。