2016-04-13 140 views
-1

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

我也试图消除临时列表,直接添加元素​​这样的:

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 

最后一组将继续出现ñ倍。有关如何解决这个问题的任何提示?

回答

1

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

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

所以,你在做什么是分配给个别项目的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 

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

编辑 - 好的,这里有一个更详细的解释。
也许关键概念之一是列表不是其他对象的容器;他们仅仅持有对其他对象的引用。
另一个关键概念是,当您更改列表中的项目(项目分配)时,并未将整个列表对象变为另一个对象。你只是在改变一个参考。这是我们在许多情况下认为理所当然的事情,但是当我们想要事情走向另一条路并“回收”列表时,某种程度上会变得违反直觉。

正如我在评论中写的那样,如果list是一只名为的猫,毛茸茸的,每当你追加你创建一个指向Fluffy的镜像。所以你可以用派对帽给Fluffy穿上衣服,把镜子指向它,然后给蓬松小丑的鼻子,穿上另一面镜子,然后穿着蓬松的芭蕾舞演员,添加第三面镜子,当你看着镜子时,所有的其中三人将展示芭蕾舞演员蓬松。 (对不起蓬松)。

我的意思是,在你的第一个脚本,实践当你追加:由我所提到的第一个概念,你是不是做lines包含的当前状态

lines.append(line) 

line作为一个单独的对象。您正在附加对line列表的引用。

当你这样做,

line[i] = elt 

由第二个概念,当然line总是相同的对象;你只需要改变第i个的位置。

这就是为什么在您的脚本末尾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]ñ引用。

你所做的只是立即创建蓬松和三面镜子指向他。
实际上,如果您更改lines[0][2]lines[1][2],您只需更改同一个毛茸茸的相同物品[2]。

你其实想什么做的是,

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

它创建三个不同的猫 - 我的意思是,列表,并有lines点三。

+0

谢谢你的解释。但为什么“行”只附加最后一行“行”?我每次都在改变“行”,不应该每次都附加(在if语句中)? – Ouss4

+0

@ Ouss4这不是你应该看到的方式。有一个关键的区别(这将是你通过解决这个问题学到的具体的东西),命名一个对象和单独分配给一个对象中的一个项目。 – Roberto

+0

@ Ouss4试图看到它是这样的: 我有一只叫做毛茸茸的猫。 (1)我会在上面放一顶绿色的帽子。 我会在Fluffy有一个镜像点。 (2)现在我要在它上面放一个小丑帽子。 我在Fluffy会有第二个镜像点。 (3)现在,我要打扮成芭蕾舞演员。 我在Fluffy会有第三个镜像点。 (4)奇怪的是,所有的三面镜子都显示出蓬松扮成芭蕾舞演员。 ...所以为了这个工作,你需要使用三只猫(三个不同的物体),而不是改变同一只猫的帽子。 – Roberto

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]],等等。

+0

这真的很整洁谢谢你。我试图用列表理解来解决这个问题,但是却试图解决最后一个问题。 – Ouss4