Danh sách Python so với Mảng - khi nào nên sử dụng?


375

Nếu bạn đang tạo mảng 1d, bạn có thể triển khai nó dưới dạng Danh sách hoặc sử dụng mô-đun 'mảng' trong thư viện chuẩn. Tôi đã luôn sử dụng Danh sách cho mảng 1d.

Lý do hoặc hoàn cảnh mà tôi muốn sử dụng mô-đun mảng là gì?

Là nó để tối ưu hóa hiệu suất và bộ nhớ, hoặc tôi đang thiếu một cái gì đó rõ ràng?

Câu trả lời:


438

Về cơ bản, danh sách Python rất linh hoạt và có thể chứa dữ liệu hoàn toàn không đồng nhất, tùy ý và chúng có thể được thêm vào rất hiệu quả, trong thời gian không đổi được khấu hao . Nếu bạn cần thu nhỏ và phát triển danh sách của mình một cách hiệu quả và không gặp rắc rối, chúng là cách để đi. Nhưng họ sử dụng một không gian nhiều hơn mảng C .

Mặt array.arraykhác, loại chỉ là một lớp bao bọc mỏng trên mảng C. Nó chỉ có thể chứa dữ liệu đồng nhất, tất cả cùng loại và do đó, nó chỉ sử dụng sizeof(one object) * lengthbyte bộ nhớ. Hầu hết, bạn nên sử dụng nó khi bạn cần hiển thị một mảng C cho một phần mở rộng hoặc một cuộc gọi hệ thống (ví dụ, ioctlhoặc fctnl).

array.arraycũng là một cách hợp lý để biểu diễn một chuỗi có thể thay đổi trong Python 2.x ( array('B', bytes)). Tuy nhiên, Python 2.6+ và 3.x cung cấp một chuỗi byte có thể thay đổi như bytearray.

Tuy nhiên, nếu bạn muốn thực hiện toán học trên một mảng dữ liệu số đồng nhất, thì tốt hơn hết bạn nên sử dụng NumPy, có thể tự động vector hóa các hoạt động trên các mảng đa chiều phức tạp.

Để làm cho một câu chuyện dài ngắn : array.arrayhữu ích khi bạn cần một mảng dữ liệu C đồng nhất vì những lý do khác ngoài làm toán .


9
Numpy.ndarray có cùng dấu chân bộ nhớ với mảng.array không?
Gordon Bean

6
@Gordon, nó sẽ rất giống nhau trong trường hợp một mảng lớn, liền kề: cả hai sẽ yêu cầu sizeof(element)byte (số phần tử) byte, cộng với một tiêu đề cố định nhỏ cho chi phí. Tuy nhiên, ndarray có một số tùy chọn nâng cao để xử lý các mảng rời rạc và thưa thớt và tôi nghĩ rằng một số chiến lược có thể cắm được để phân bổ bộ nhớ cho các mảng lớn ... một số tính năng nâng cao này sẽ khiến người dùng ít bộ nhớ hơn , trong khi các tính năng khác sẽ cải thiện hiệu suất bằng cách sử dụng nhiều hơn ký ức.
Dan Lenski

Cũng hữu ích khi bộ nhớ là một vấn đề như khi lập trình bộ điều khiển vi mô với micropython
janscas

Người ta có thể tra cứu phần tử thứ i của một mảng trong một thời gian không đổi, trong khi trong danh sách được liên kết, nó sẽ có thứ tự 'n' trong trường hợp xấu nhất. Thời gian tra cứu của phần tử thứ i trong danh sách python là gì?
Nithish Inpursuit Ofhappiness 19/07/17

7
@NithishInpursuitOfhappiness, danh sách Python không phải là danh sách được liên kết. Nó được biểu diễn bên trong dưới dạng một mảng và có các đặc điểm phức tạp cùng thời gian với ArrayList của Java. Do đó, việc lấy và thiết lập phần tử thứ i của danh sách Python cần thời gian không đổi . Việc thêm một phần tử vào danh sách Python mất thời gian không đổi được khấu hao vì kích thước mảng được nhân đôi khi hết dung lượng. Việc chèn một phần tử vào hoặc xóa từ giữa danh sách Python sẽ mất thời gian O (n) vì các phần tử cần được dịch chuyển. Để tham khảo, hãy xem: wiki.python.org/moin/TimeComplexity
geofflee

66

Đối với hầu hết các trường hợp, danh sách bình thường là sự lựa chọn đúng đắn. Mô-đun mảng giống như một trình bao bọc mỏng hơn các mảng C, cung cấp cho bạn loại bộ chứa được gõ mạnh (xem tài liệu ), với quyền truy cập vào các loại giống C hơn như ký hiệu ngắn hoặc không dấu, không phải là một phần của được xây dựng -in các loại. Tôi muốn nói chỉ sử dụng mô-đun mảng nếu bạn thực sự cần nó, trong tất cả các trường hợp khác gắn với danh sách.


3
Có thể, không bao giờ sử dụng nó thực sự mặc dù, nhưng sẽ rất thú vị để chạy một số điểm chuẩn vi mô.
André

13
Trên thực tế, tôi đã thực hiện một bài kiểm tra nhanh - tôi đã tính thời gian tổng hợp một danh sách với 100 triệu mục và cùng một bài kiểm tra với mảng tương ứng, và danh sách này thực sự nhanh hơn khoảng 10%.
Moe

38
Danh sách nhanh hơn, bởi vì các thao tác trên dữ liệu "thô" cần liên tục tạo và hủy các đối tượng python khi đọc từ hoặc ghi vào mảng.
tzot

7
@Moe, như tôi đã chỉ ra trong câu trả lời của tôi ở trên, Python tích hợp trong arrayđược không có nghĩa là để làm toán . Nếu bạn thử NumPy ndarrayđể tổng hợp một mảng 10 ^ 8 số, nó sẽ hoàn toàn listbiến mất. @tzot có ý tưởng đúng về lý do tại sao tích hợp arraychậm cho toán học.
Dan Lenski

2
Tôi vừa thử nó, numpy nhanh hơn 86,6 lần trên máy của tôi.
Đánh dấu

53

Mô-đun mảng là một trong những điều mà bạn có thể không cần nếu bạn không biết lý do tại sao bạn sẽ sử dụng nó (và lưu ý rằng tôi không cố nói điều đó theo cách hạ thấp!) . Hầu hết thời gian, mô-đun mảng được sử dụng để giao tiếp với mã C. Để cung cấp cho bạn câu trả lời trực tiếp hơn cho câu hỏi của bạn về hiệu suất:

Mảng hiệu quả hơn danh sách cho một số sử dụng. Nếu bạn cần phân bổ một mảng mà bạn BIẾT sẽ không thay đổi, thì mảng có thể nhanh hơn và sử dụng ít bộ nhớ hơn. GvR có một giai thoại tối ưu hóa trong đó mô-đun mảng xuất hiện để trở thành người chiến thắng (đọc lâu, nhưng đáng giá).

Mặt khác, một phần lý do tại sao danh sách chiếm nhiều bộ nhớ hơn mảng là vì python sẽ phân bổ một vài phần tử bổ sung khi tất cả các phần tử được phân bổ được sử dụng. Điều này có nghĩa là việc thêm các mục vào danh sách nhanh hơn. Vì vậy, nếu bạn có kế hoạch thêm các mục, một danh sách là cách để đi.

TL; DR Tôi chỉ sử dụng một mảng nếu bạn có nhu cầu tối ưu hóa đặc biệt hoặc bạn cần giao diện với mã C (và không thể sử dụng pyrex ).


1
+1 cho ví dụ cụ thể và đề cập đến lợi ích tốc độ. Câu trả lời hàng đầu khiến tôi tự hỏi, "Có sự đánh đổi bộ nhớ thời gian không?" và "Có sử dụng cho trường hợp này không phải là trường hợp bộ nhớ thấp rất bí truyền không?"
leewz

@leewz chính xác, điều này nên được coi là câu trả lời.
Gauri Shankar Badola

21

Đó là một sự đánh đổi!

ưu điểm của từng người:

danh sách

  • Linh hoạt
  • có thể không đồng nhất

mảng (ví dụ: mảng numpy)

  • mảng giá trị đồng nhất
  • đồng nhất
  • nhỏ gọn (kích thước)
  • hiệu quả (chức năng và tốc độ)
  • tiện lợi

2
câu hỏi đang đề cập đến mô-đun mảng trong python; không phải mảng numpy. Họ không có nhiều ưu điểm ngoại trừ hiệu quả kích thước. Chúng không nhanh hơn.
NONONONONO

14

Tôi hiểu rằng các mảng được lưu trữ hiệu quả hơn (nghĩa là các khối bộ nhớ liền kề so với các con trỏ tới các đối tượng Python), nhưng tôi không nhận thấy bất kỳ lợi ích hiệu năng nào. Ngoài ra, với các mảng, bạn phải lưu trữ các kiểu nguyên thủy cùng loại, trong khi danh sách có thể lưu trữ mọi thứ.


8

Các mảng thư viện chuẩn rất hữu ích cho I / O nhị phân, chẳng hạn như dịch một danh sách các int thành một chuỗi để ghi vào, giả sử, một tệp sóng. Điều đó nói rằng, như nhiều người đã lưu ý, nếu bạn sẽ thực hiện bất kỳ công việc thực tế nào thì bạn nên xem xét sử dụng NumPy.


6

Nếu bạn đang sử dụng mảng, hãy xem xét các gói numpy hoặc scipy, cung cấp cho bạn các mảng với độ linh hoạt hơn rất nhiều.


5

Mảng chỉ có thể được sử dụng cho các loại cụ thể, trong khi danh sách có thể được sử dụng cho bất kỳ đối tượng nào.

Mảng cũng chỉ có thể dữ liệu của một loại, trong khi một danh sách có thể có các mục của các loại đối tượng khác nhau.

Mảng cũng hiệu quả hơn đối với một số tính toán số.


4
Các mảng python dựng sẵn không hiệu quả về hiệu năng, chỉ có bộ nhớ.
tzot

Có những trường hợp trong đó các mảng hiệu quả hơn về mặt xử lý. Xem bài đăng của tôi dưới đây: stackoverflow.com/questions/176011/ Kẻ
Jason Baker

0

Một sự khác biệt quan trọng giữa mảng numpy và danh sách là các lát mảng là các khung nhìn trên mảng ban đầu. Điều này có nghĩa là dữ liệu không được sao chép và mọi sửa đổi đối với chế độ xem sẽ được phản ánh trong mảng nguồn.


0

Câu trả lời này sẽ tổng hợp gần như tất cả các truy vấn về thời điểm sử dụng Danh sách và Mảng:

  1. Sự khác biệt chính giữa hai loại dữ liệu này là các thao tác bạn có thể thực hiện trên chúng. Ví dụ: bạn có thể chia một mảng cho 3 và nó sẽ chia mỗi phần tử của mảng cho 3. Không thể thực hiện tương tự với danh sách.

  2. Danh sách này là một phần của cú pháp của python vì vậy nó không cần phải khai báo trong khi bạn phải khai báo mảng trước khi sử dụng nó.

  3. Bạn có thể lưu trữ các giá trị của các loại dữ liệu khác nhau trong một danh sách (không đồng nhất), trong khi trong Mảng bạn chỉ có thể lưu trữ các giá trị của cùng một loại dữ liệu (đồng nhất).

  4. Mảng là giàu chức năng và nhanh chóng, nó được sử dụng rộng rãi cho các hoạt động số học và để lưu trữ một lượng lớn dữ liệu - so với danh sách.

  5. Mảng mất ít bộ nhớ so với danh sách.


0

Liên quan đến hiệu suất, đây là một số con số so sánh danh sách python, mảng và mảng numpy (tất cả đều có Python 3.7 trên Macbook Pro 2017). Kết quả cuối cùng là danh sách python là nhanh nhất cho các hoạt động này.

# Python list with append()
np.mean(timeit.repeat(setup="a = []", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.054 +/- 0.025 msec

# Python array with append()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.104 +/- 0.025 msec

# Numpy array with append()
np.mean(timeit.repeat(setup="import numpy as np; a = np.array([])", stmt="np.append(a, [1.0])", number=1000, repeat=5000)) * 1000
# 5.183 +/- 0.950 msec

# Python list using +=
np.mean(timeit.repeat(setup="a = []", stmt="a += [1.0]", number=1000, repeat=5000)) * 1000
# 0.062 +/- 0.021 msec

# Python array using += 
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a += array.array('f', [1.0]) ", number=1000, repeat=5000)) * 1000
# 0.289 +/- 0.043 msec

# Python list using extend()
np.mean(timeit.repeat(setup="a = []", stmt="a.extend([1.0])", number=1000, repeat=5000)) * 1000
# 0.083 +/- 0.020 msec

# Python array using extend()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.extend([1.0]) ", number=1000, repeat=5000)) * 1000
# 0.169 +/- 0.034
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.