2015-05-14 45 views
1

比方說錯誤列表操作

>>> a = [1,2,3,4,5] 

而且我要像

>>> b 
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] 

這裏的輸出是我的代碼:

class Child(object): 
    def get_lines(self): 
     a = [1,2,3,4,5]    
     b=[] 
     c=[] 
     j=0 
     for i in a: 
      print i 
      b.append(i) 
      print b 
      c.insert(j,b) 

      j=j+1 
     print c 


son= Child() 
son.get_lines() 

當我在環打印列表b,它給:

1 
[1] 
2 
[1, 2] 
3 
[1, 2, 3] 
4 
[1, 2, 3, 4] 
5 
[1, 2, 3, 4, 5] 

,輸出是:

[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]] 

我在哪裏做出錯誤的代碼?

+0

http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python –

回答

5

b總是相同的列表對象(注意:我已經改變了print creturn c):

>>> map(id, Child().get_lines()) 
... 
[49021616, 49021616, 49021616, 49021616, 49021616] 

c包含對同一列表的五個引用。我想你想要的是:

class Child(object): 

    def get_lines(self): 
     a = [1, 2, 3, 4, 5]    
     return [a[:x+1] for x in range(len(a))] 

這使得部分a一個淺拷貝(或全部)每個步驟:

>>> Child().get_lines() 
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] 
2

替換:

c.insert(j,b) 

有:

c.append(b[:]) 

,然後再試一次。您需要複製b。否則,您一次又一次地添加相同的b,從而導致所有指數的完整列表。 'b [:]'複製列表。

該解決方案不相同,但有一點短:

a = [1, 2, 3, 4, 5] 
c = [] 
for i in range(1, len(a) + 1): 
    c.append(a[:i]) 

現在c是:

[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] 

a[:i]片名單a從一開始就排除了指數i。 在這種情況下,它確實有a[:1]a[:2]等等。 a[:1]新建一個清單[1], a[:2]新清單[1, 2,]等。使用append()更簡單,insert()

另一種選擇是一個列表理解:

a = [1, 2, 3, 4, 5] 
[a[:i] for i in range(1, len(a) + 1)] 

也導致:

[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] 
+0

感謝邁克......但切片是如何工作的正確 –

+0

@JayVenkat我不明白你的問題。 –

+0

對不起,現在我明白你所交付的東西:) –

1

您在列表中插入c相同b五倍。由於列表實際上包含對象的引用而不是副本,因此您有5次引用同一個b列表,其中您已經連續添加了1,2,3,4,5。所以結果。

相反,您必須添加副本列表B的

def get_lines(self): 
    a = [1,2,3,4,5]    
    b=[] 
    c=[] 
    j=0 
    for i in a: 
     print i 
     b.append(i) 
     print b 
     c.insert(j,b[:]) # forces insertion of a copy 

     j=j+1 
    print c 
0

在循環中,b價值仍然存在,因爲它是一個可變的對象。因此,當您打印c時,會顯示最後一個值b

而不是使用b作爲臨時變量的,可以直接使用a如下:

class Child(object): 
    def get_lines(self): 
     a = [1,2,3,4,5] 
     b = [] 
     for index, element in enumerate(a, 1): 
      b.append(x[:index]) 
     return b 


son= Child() 
son.get_lines() 
2

在這裏,在這種情況下,你不應該附加價值的列表對象(B)。 因爲listmutable,它會引用內存中完全相同的對象直到重新分配爲止。

>>> b=[] 
>>> b.append(1) 
>>> id(b) 
4337935424 
>>> b.append(2) 
>>> id(b) 
4337935424 
>>> b.append(3) 
>>> id(b) 
4337935424 
>>> b = [1, 2, 3, 4] 
>>> id(b) 
4337942608 

以便在您的代碼c中將對同一列表進行五次引用。

它將指示一個新對象,然後(儘可能)將引用插入到原始對象中。

>>> class Child(object): 
... 
...  def get_lines(self): 
...   a = [1, 2, 3, 4, 5] 
...   return map(lambda x: a[:x+1], range(len(a))) 
... 
>>> Child().get_lines() 
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] 
+0

嘿你的解釋使我的疑惑變得完美。另外,我對**地圖**有懷疑。你爲什麼要用這個結構,還有lambda ...在jonrsharpe的回答中,他沒有使用那種結構。哪個時間複雜度較低? –

+0

是的,你是對的Jay,這是什麼,但我在簡單的迭代中使用lambda。 – ManikandanV

+0

@JayVenkat根據時間複雜度'timeit'表明列表理解(我的)是最快的,那麼副本(Mike/Serge)和'map'(Manikandan)是最慢的,但這不是很大(2.04 s,2.43s和2.85s) – jonrsharpe