2016-04-13 134 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