2012-06-27 82 views
6

Dưới đây là một chương trình rất đơn giản:Python: cách nối thêm các phần tử mới vào danh sách danh sách?

a = [[]]*3 

print str(a) 

a[0].append(1) 
a[1].append(2) 
a[2].append(3) 

print str(a[0]) 
print str(a[1]) 
print str(a[2]) 

Đây là kết quả tôi đã mong đợi:

[[], [], []] 
[1] 
[2] 
[3] 

Nhưng thay vào đó tôi có được điều này:

[[], [], []] 
[1, 2, 3] 
[1, 2, 3] 
[1, 2, 3] 

Có thực sự là cái gì tôi làm không đến đây!

+0

Bạn nên sử dụng một danh sách các _lists_ thay vì một danh sách (giống nhau) danh sách như infers tiêu đề. –

Trả lời

12

Bạn phải làm

a = [[] for i in xrange(3)] 

không

a = [[]]*3 

Bây giờ nó hoạt động:

$ cat /tmp/3.py 
a = [[] for i in xrange(3)] 

print str(a) 

a[0].append(1) 
a[1].append(2) 
a[2].append(3) 

print str(a[0]) 
print str(a[1]) 
print str(a[2]) 

$ python /tmp/3.py 
[[], [], []] 
[1] 
[2] 
[3] 

Khi bạn làm điều gì đó như a = [[]]*3 bạn nhận được cùng một danh sách [] ba lần trong một danh sách . Cùng một có nghĩa là khi bạn thay đổi một trong số chúng, bạn thay đổi tất cả chúng (vì chỉ có một danh sách được tham chiếu ba lần).

Bạn cần tạo ba danh sách độc lập để giải quyết vấn đề này. Và bạn làm điều đó với một danh sách hiểu. Bạn xây dựng ở đây một danh sách bao gồm các danh sách trống độc lập []. Danh sách trống mới sẽ được tạo cho mỗi lần lặp qua xrange(3) (sự khác biệt giữa rangexrange không quá quan trọng trong trường hợp này, nhưng xrange là một chút tốt hơn vì nó không tạo danh sách đầy đủ các số và chỉ trả về một đối tượng trình lặp).

+2

Sẽ tốt hơn w/giải thích và sử dụng 'xrange' – okm

+1

@okm trừ khi nó là python 3x :) – Trufa

5

Khi bạn viết:

a = [[]]*3 

Bạn sẽ không thực hiện 3 bản sao của danh sách trống bên trong, nhưng thay vào đó bạn làm tài liệu tham khảo từ 3 đến cùng một đối tượng.

Theo cùng một cách, nếu bạn làm:

b = [1,2,3] 
c = b 
c.append(4) 
print b 

Bạn nhận được như kết quả:

[1, 2, 3, 4] 

Đó là vì b và c là hai tài liệu tham khảo khác nhau (bạn có thể nói hai tên gọi khác nhau) vào cùng một danh sách. Bạn có thể thay đổi đối tượng từ bất kỳ tham chiếu nào, nhưng bạn sẽ thấy kết quả từ tất cả chúng, vì chúng trỏ đến cùng một thứ.

5

Vấn đề cơ bản với cách tiếp cận của bạn là khi bạn nhân danh sách ba, danh sách kết quả chứa ba của cùng một danh sách. Vì vậy, a[0], a[1]a[2] tất cả đều tham chiếu cùng một điều. Khi bạn gắn thêm vào bất kỳ thứ gì trong số này, bạn sẽ thêm vào cùng một danh sách. Đây là lý do tại sao hiệu ứng của các cuộc gọi append() của bạn dường như bị lặp lại.

Thay vào đó, hãy tạo danh sách danh sách của bạn mà không tham chiếu cùng một danh sách. Ví dụ, bạn có thể sử dụng danh sách hiểu, như vậy.

[[] for i in range(3)] 
1

Thực sự có điều gì đó tôi không đến đây!

a = [[]]*3 vấn đề ở đây là bạn đang đặt danh sách thành cùng một tham chiếu, vì mảng cũng như từ điển được lưu dưới dạng tham chiếu.

>>> a = [[]]*3 
>>> a[0] is a[1] or a[0] is a[2] 
True 
>>> a[0] is a[1] or a[0] is a[2] or a[1] is a[2] 
True 
>>> 

điều tương tự xảy ra nếu bạn làm một = [{}] * 3`

như vậy bạn phải cẩn thận, bạn có thể làm một trong hai danh sách hiểu [[] for _ in xrange(3)] hoặc tĩnh xác định tất cả 3 mảng của bạn [[], [], []].

>>> a = [[] for _ in xrange(3)] 
>>> a[0] is a[1] or a[0] is a[2] or a[1] is a[2] 
False 
>>> 
2

này sẽ cung cấp cho bạn một ý tưởng rõ ràng, trong l tất cả các đối tượng có cùng một id() và tất cả đều có thể thay đổi để chỉnh sửa bất kỳ một trong số họ sẽ tự động chỉnh sửa khác quá, như tất cả họ đều chỉ refernces đến một cùng đối tượng với id = 18671936 và trong m tất cả có id khác nhau(), vì vậy tất cả chúng là các đối tượng khác nhau.

>>> l = [[]]*4 
>>> for x in l: 
     print(id(x)) 

18671936 
18671936 
18671936 
18671936 

>>> m=[[],[],[],[]] 
>>> for x in m: 
     print(id(x)) 

10022256 
18671256 
18672496 
18631696 

Vì vậy, bạn nên tạo danh sách của bạn như thế này:

>>> a=[[] for _ in range(4)] 
>>> a[0].append(1) 
>>> a[2].append(5) 
>>> a 
[[1], [], [5], []] 
Các vấn đề liên quan