Sự khác biệt giữa Mảng và Danh sách trong scala


141

Trong trường hợp nào tôi nên sử dụng Array (Buffer) và List (Buffer). Chỉ có một sự khác biệt mà tôi biết là các mảng là không biến đổi và các danh sách là covariant. Nhưng những gì về hiệu suất và một số đặc điểm khác?

Câu trả lời:


155

Cấu trúc bất biến

Scala Listlà một bất biến cấu trúc dữ liệu đệ quy mà là một cấu trúc cơ bản như vậy trong Scala, mà bạn nên (có lẽ) được sử dụng nó nhiều hơn một Array(mà thực sự có thể thay đổi - những analog bất biến của ArrayIndexedSeq).

Nếu bạn đang đến từ một nền tảng Java, thì song song rõ ràng là khi nào sử dụng LinkedListqua ArrayList. Cái trước thường được sử dụng cho các danh sách chỉ được duyệt qua (và kích thước không được biết trước) trong khi cái sau nên được sử dụng cho các danh sách có kích thước đã biết (hoặc kích thước tối đa) hoặc truy cập ngẫu nhiên nhanh là quan trọng.

Cấu trúc đột biến

ListBuffercung cấp một chuyển đổi thời gian không đổi thành một Listlý do duy nhất để sử dụng ListBuffernếu việc chuyển đổi sau này là bắt buộc.

Scala Arraynên được triển khai trên JVM bởi một mảng Java và do đó, một trình diễn Array[Int]có thể hiệu quả hơn (như một int[]) so với List[Int](sẽ đóng hộp nội dung của nó, trừ khi bạn đang sử dụng các phiên bản Scala mới @specializednhất có tính năng mới ) .

Tuy nhiên, tôi nghĩ rằng việc sử dụng Arrays trong Scala nên được giữ ở mức tối thiểu vì cảm giác như bạn thực sự cần biết những gì đang diễn ra dưới mui xe để quyết định xem mảng của bạn có thực sự được hỗ trợ bởi kiểu nguyên thủy cần thiết hay không được đóng hộp như một loại bao bọc.



130

Ngoài các câu trả lời được đăng, đây là một số chi tiết cụ thể.

Trong khi một Array[A]nghĩa đen là một mảng Java, thì a List[A]là một cấu trúc dữ liệu bất biến là Nil(danh sách trống) hoặc bao gồm một cặp (A, List[A]).

Hiệu suất khác biệt

                          Array  List
Access the ith element    θ(1)   θ(i)
Delete the ith element    θ(n)   θ(i)
Insert an element at i    θ(n)   θ(i)
Reverse                   θ(n)   θ(n)
Concatenate (length m,n)  θ(n+m) θ(n)
Count the elements        θ(1)   θ(n)

Sự khác biệt về bộ nhớ

                          Array  List
Get the first i elements  θ(i)   θ(i)
Drop the first i elements θ(n-i) θ(1)
Insert an element at i    θ(n)   θ(i)
Reverse                   θ(n)   θ(n)
Concatenate (length m,n)  θ(n+m) θ(n)

Vì vậy, trừ khi bạn cần truy cập ngẫu nhiên nhanh chóng, cần phải đếm các yếu tố hoặc vì lý do nào đó bạn cần cập nhật mang tính hủy diệt, Listthì tốt hơn là một Array.


Những Os này có phải xem xét thời gian để sao chép Danh sách không? Tôi giả sử bạn đang làm bài kiểm tra như thế này, vd : list = list.drop(i). Hoặc, Có xảy ra một số phép thuật đằng sau mui xe?

2
Điều này sẽ đưa vào danh sách sao chép tài khoản và mảng khi cần thiết. Lưu ý rằng những thứ như dropkhông bao giờ cần sao chép phần danh sách không bị loại bỏ. Ví dụ , (x::xs).drop(1)chính xác xs, không phải là "bản sao" của xs.
Apocalisp

6
Những triệu chứng này không liên quan gì đến Scala. Cấu trúc dữ liệu tương tự trong C sẽ chính xác nhanh đến các yếu tố không đổi.
Apocalisp

1
@Apocalisp Bạn có tài liệu tham khảo hoặc trong những điều kiện nào bạn đã xác định thông tin này?
Phil

1
@Phil Đây là những triệu chứng không triệu chứng, không phải phép đo. Họ sẽ giữ đúng trong mọi điều kiện.
Apocalisp

18

Một mảng có thể thay đổi, nghĩa là bạn có thể thay đổi các giá trị của từng chỉ mục, trong khi Danh sách (theo mặc định) là không thay đổi, có nghĩa là một danh sách mới được tạo mỗi khi bạn thực hiện sửa đổi. Trong hầu hết các trường hợp, nó là một "chức năng" phong cách hơn để làm việc với các kiểu dữ liệu bất biến và có lẽ bạn nên thử và sử dụng một danh sách với cấu trúc như yield, foreach, matchvà vân vân.

Đối với các đặc tính hiệu suất, một Mảng nhanh hơn với quyền truy cập ngẫu nhiên vào các phần tử, trong khi Danh sách nhanh hơn khi thêm (thêm) các phần tử mới. Lặp đi lặp lại trên chúng là so sánh.


@leonm - apols, tôi nghĩ OP đã hỏi riêng về các lớp * Buffer, tôi nhận ra rằng họ cũng đang hỏi về những cái "bình thường"!
oxbow_lakes

2
Việc nối thêm vào ArrayBuffer thường nhanh hơn so với việc thêm vào Danh sách (hoặc thêm một phần tử vào ListBuffer) vì các danh sách yêu cầu tạo đối tượng trình bao trong khi ArrayBuffer chỉ cần sao chép đối tượng (trung bình khoảng hai lần) vào một mảng mới . Hai bản sao thường nhanh hơn một lần tạo đối tượng, do đó, ArrayBuffer nối thêm thường đánh bại phần bổ sung Danh sách.
Rex Kerr

mảng hoạt động nhanh hơn nhiều so với danh sách khi iterate over, vì bộ đệm
Bin
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.