Tạo danh sách các mục duy nhất lặp lại N lần


523

Tôi muốn tạo một loạt các danh sách, tất cả các độ dài khác nhau. Mỗi danh sách sẽ chứa cùng một phần tử e, nthời gian lặp lại (trong đó n= độ dài của danh sách).

Làm cách nào để tạo danh sách mà không sử dụng cách hiểu danh sách [e for number in xrange(n)]cho mỗi danh sách?

Câu trả lời:


778

Bạn cũng có thể viết:

[e] * n

Bạn nên lưu ý rằng nếu e là một danh sách trống, bạn sẽ nhận được một danh sách với n tham chiếu đến cùng một danh sách, không phải n danh sách trống độc lập.

Kiểm tra năng suất

Thoạt nhìn, dường như lặp lại là cách nhanh nhất để tạo một danh sách với n phần tử giống hệt nhau:

>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

Nhưng chờ đã - đó không phải là một thử nghiệm công bằng ...

>>> itertools.repeat(0, 10)
repeat(0, 10)  # Not a list!!!

Hàm itertools.repeatkhông thực sự tạo danh sách, nó chỉ tạo một đối tượng có thể được sử dụng để tạo danh sách nếu bạn muốn! Hãy thử lại lần nữa, nhưng chuyển đổi thành một danh sách:

>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

Vì vậy, nếu bạn muốn một danh sách, sử dụng [e] * n. Nếu bạn muốn tạo ra các yếu tố một cách lười biếng, hãy sử dụng repeat.


23
Rất có khả năng hiệu suất tạo danh sách với các yếu tố giống hệt nhau sẽ là một thành phần quan trọng trong hiệu suất của chương trình python.
Arthur

11
Như đã đề cập ở trên, nếu e là một danh sách trống [[]] * ncó thể tạo ra kết quả bất ngờ. Để tạo danh sách phụ trống duy nhất , hãy sử dụng để hiểu:[[] for i in range(0,n)]
Josiah Yoder

149
>>> [5] * 4
[5, 5, 5, 5]

Hãy cẩn thận khi mục được lặp lại là một danh sách. Danh sách sẽ không được nhân bản: tất cả các yếu tố sẽ tham chiếu đến cùng một danh sách!

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]

80

Tạo danh sách các mục duy nhất lặp lại n lần trong Python

Vật phẩm bất biến

Đối với các mặt hàng bất biến, như Không có, bools, ints, float, chuỗi, tuples hoặc fro chục, bạn có thể làm như thế này:

[e] * 4

Lưu ý rằng điều này tốt nhất chỉ được sử dụng với các mục không thay đổi (chuỗi, tuples, fro chục,) trong danh sách, bởi vì tất cả chúng đều trỏ đến cùng một mục trong cùng một vị trí trong bộ nhớ. Tôi sử dụng điều này thường xuyên khi tôi phải xây dựng một bảng với một lược đồ gồm tất cả các chuỗi, do đó tôi không phải đưa ra một bản đồ dự phòng cao cho một ánh xạ.

schema = ['string'] * len(columns)

Vật phẩm có thể thay đổi

Tôi đã sử dụng Python từ lâu và tôi chưa bao giờ thấy trường hợp sử dụng nào mà tôi sẽ làm như trên với một ví dụ có thể thay đổi. Thay vào đó, để có được, giả sử, một danh sách trống có thể thay đổi, thiết lập hoặc đọc chính tả, bạn nên làm một cái gì đó như thế này:

list_of_lists = [[] for _ in columns]

Gạch dưới chỉ đơn giản là một tên biến ném trong bối cảnh này.

Nếu bạn chỉ có số, đó sẽ là:

list_of_lists = [[] for _ in range(4)]

Điều _này không thực sự đặc biệt, nhưng trình kiểm tra kiểu môi trường mã hóa của bạn có thể sẽ phàn nàn nếu bạn không có ý định sử dụng biến và sử dụng bất kỳ tên nào khác.


Hãy cẩn thận khi sử dụng phương pháp bất biến với các vật phẩm có thể thay đổi:

Coi chừng làm điều này với các đối tượng có thể thay đổi , khi bạn thay đổi một trong số chúng, tất cả chúng đều thay đổi vì tất cả chúng đều là cùng một đối tượng:

foo = [[]] * 4
foo[0].append('x')

foo bây giờ trở lại:

[['x'], ['x'], ['x'], ['x']]

Nhưng với các đối tượng bất biến, bạn có thể làm cho nó hoạt động vì bạn thay đổi tham chiếu, không phải đối tượng:

>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]

>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

Nhưng một lần nữa, các đối tượng có thể thay đổi là không tốt cho điều này, bởi vì các hoạt động tại chỗ thay đổi đối tượng, không phải là tham chiếu:

l = [set()] * 4
>>> l[0] |= set('abc')    
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]

26

Itertools có một chức năng chỉ dành cho điều đó:

import itertools
it = itertools.repeat(e,n)

Tất nhiên itertoolscung cấp cho bạn một iterator thay vì một danh sách. [e] * ncung cấp cho bạn một danh sách, nhưng, tùy thuộc vào những gì bạn sẽ làm với các chuỗi đó, itertoolsbiến thể có thể hiệu quả hơn nhiều.


13

Như những người khác đã chỉ ra, sử dụng toán tử * cho một đối tượng có thể thay đổi sẽ nhân đôi các tham chiếu, vì vậy nếu bạn thay đổi một tham chiếu, bạn sẽ thay đổi tất cả. Nếu bạn muốn tạo các phiên bản độc lập của một đối tượng có thể thay đổi, cú pháp xrange của bạn là cách Pythonic nhất để làm điều này. Nếu bạn cảm thấy phiền vì có một biến được đặt tên không bao giờ được sử dụng, bạn có thể sử dụng biến gạch dưới ẩn danh.

[e for _ in xrange(n)]

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.