Có bao giờ một lý do để sử dụng một mảng khi danh sách có sẵn? [đóng cửa]


30

Có vẻ như List<T>trong C # có thể làm mọi thứ mà một mảng có thể làm và hơn thế nữa, và dường như cũng hiệu quả về bộ nhớ và hiệu năng như một mảng.

Vậy tại sao tôi lại muốn sử dụng một mảng?

Tôi rõ ràng không hỏi về các trường hợp API hoặc ràng buộc bên ngoài khác (tức là hàm Chính) yêu cầu tôi sử dụng một mảng ... Tôi chỉ hỏi về việc tạo cấu trúc dữ liệu mới trong mã của riêng tôi.


56
Để thực hiệnList<T>
ratchet freak

43
is also just as efficient in memory and performance as an array- ừm. Bạn đã có được khái niệm đó từ đâu?
Oded

12
Nhiều thứ nguyên như var test = new string[5,5];)
Knerd

7
Ngoài ra còn có mảng byte [] thường được sử dụng.
SBoss

11
Đối với C # cụ thể, Eric Lippert đã viết về điều này trên blog.msdn.com/b/ericlippert/archive/2008/09/22/ .
Mephy

Câu trả lời:


26

Lý do tương tự tôi không lái xe tải khi đi làm. Tôi không sử dụng cái gì đó mà tôi sẽ không sử dụng các tính năng của.

Trước hết, một mảng là một cấu trúc nguyên thủy nên một mảng nhanh hơn và hiệu quả hơn một Danh sách <> chắc chắn, vì vậy đối số của bạn không đúng. Array cũng có sẵn ở khắp mọi nơi và được các nhà phát triển sử dụng các ngôn ngữ và nền tảng khác nhau.

Lý do quan trọng nhất tôi sử dụng một mảng thay vì Danh sách <> là để ngụ ý rằng dữ liệu có độ dài cố định . Nếu tôi sẽ không thêm hoặc xóa bất kỳ mục nào khỏi bộ sưu tập dữ liệu đó, tôi muốn chắc chắn rằng loại đó phản ánh điều đó.

Một điều nữa là giả sử bạn đang thực hiện cấu trúc dữ liệu mới và bạn đã đọc một số bài viết về nó. Bây giờ trong khi thực hiện các thuật toán cụ thể, bạn không thể luôn dựa vào việc triển khai loại người khác có mục đích chung. Nó thay đổi từ .NET sang Mono và thậm chí giữa các phiên bản khác nhau của khung.

Và đôi khi dễ dàng chuyển một đoạn mã sử dụng một mảng thay vì kiểu phụ thuộc khung.


4
Làm thế nào là một mảng "nhanh hơn" một danh sách, xem xét điều đó List<T>được thực hiện bằng cách sử dụng một mảng? Nếu bạn biết trước phần tử đếm (mà bạn phải biết, khi sử dụng một mảng), bạn có thể sử dụng kiến ​​thức đó khi khởi tạo danh sách.
Theodoros Chatzigiannakis

1
@TheodorosChatzigiannakis Khi sử dụng một mảng, chúng tôi phân bổ bộ nhớ và chỉ cần thực hiện các bài tập, malloc () đơn giản, không có chi phí. Khi bạn đang sử dụng Danh sách <>, bạn sẽ "Thêm" các mục và khi thêm các mục Danh sách <> thực hiện một số kiểm tra ranh giới và gọi phương thức SureCapacity sẽ sao chép nội dung sang một mảng mới được phân bổ nếu dung lượng hiện tại không đủ. Điều đó có nghĩa là nếu bạn không cần phân bổ động bộ nhớ mới, hiệu suất của List không tốt bằng mảng.
Mert Akcakaya

4
Những gì bạn đang nói là đúng, nhưng nó giả định rằng một trong hai chúng ta không biết số lượng nguyên tố trước (trong trường hợp này, mảng là không hữu ích anyway) hoặc là chúng ta làm biết đếm yếu tố trước nhưng chúng tôi cố tình không sử dụng nó trong trường hợp của danh sách. Nếu chúng ta làm sử dụng các tính yếu tố để khởi tạo danh sách với công suất mong muốn, chúng tôi chỉ nhận được một phân bổ mảng (cho đến khi bạn đạt được điều đó công suất), do đó chúng tôi trả chi phí thực hiện tương tự. Tất cả các hoạt động phổ biến khác đều bằng nhau (tìm kiếm, truy xuất theo chỉ mục, gán theo chỉ mục), ngoại trừ các bổ sung thêm (mà các mảng không có gì cả).
Theodoros Chatzigiannakis

3
@TheodorosChatzigiannakis: Mảng nhanh hơn so với danh sách. Chỉ cần chạy một điểm chuẩn đơn giản để kiểm tra.
Mehrdad

1
@TheodorosChatzigiannakis, Có, nhưng vẫn có kiểm tra ranh giới.
Mert Akcakaya

18

Tất nhiên, bạn cần các mảng để quản lý bộ sưu tập các cấu trúc có thể thay đổi và chúng ta sẽ làm gì nếu không có chúng.

struct EvilMutableStruct { public double X; } // don't do this

EvilMutableStruct[] myArray = new EvilMutableStruct[1];
myArray[0] = new EvilMutableStruct()
myArray[0].X = 1; // works, this modifies the original struct

List<EvilMutableStruct> myList = new List<EvilMutableStruct>();
myList.Add(new EvilMutableStruct());
myList[0].X = 1; // does not work, the List will return a *copy* of the struct

(lưu ý rằng có thể có một số trường hợp trong đó một mảng cấu trúc có thể thay đổi là mong muốn, nhưng thông thường hành vi khác nhau này của các cấu trúc có thể thay đổi trong các mảng so với các bộ sưu tập khác là một nguồn lỗi nên tránh)


Nghiêm trọng hơn, bạn cần một mảng nếu bạn muốn truyền một phần tử bằng cách tham chiếu . I E

Interlocked.Increment(ref myArray[i]);  // works
Interlocked.Increment(ref myList[i]);   // does not work, you can't pass a property by reference

Điều đó có thể hữu ích cho mã chủ đề không khóa.


Bạn cần một mảng nếu bạn muốn nhanh chóng và hiệu quả để khởi tạo bộ sưu tập kích thước cố định của mình với giá trị mặc định .

double[] myArray = new double[1000]; // contains 1000 '0' values
                                     // without further initialisation

List<double> myList = new List<double>(1000) // internally contains 1000 '0' values, 
                                             // since List uses an array as backing storage, 
                                             // but you cannot access those
for (int i =0; i<1000; i++) myList.Add(0);   // slow and inelegant

(lưu ý rằng có thể triển khai một hàm tạo cho Danh sách giống như vậy, chỉ là c # không cung cấp tính năng này)


bạn cần một mảng nếu bạn muốn sao chép một cách hiệu quả các phần của bộ sưu tập

Array.Copy(array1, index1, array2, index2, length) // can't get any faster than this

double[,] array2d = new double[10,100];
double[] arraySerialized = new double[10*100];
Array.Copy(array2d, 0, arraySerialized, 0, arraySerialized.Length);
// even works for different dimensions

(một lần nữa, đây cũng là điều có thể được triển khai cho Danh sách, nhưng tính năng này không tồn tại trong c #)


Nếu một loại được cho là đại diện cho một nhóm các biến liên quan nhưng độc lập được dán cùng với băng keo (ví dụ: tọa độ của một điểm), cấu trúc trường tiếp xúc là đại diện tốt nhất. Nếu một biến được cho là chứa một nhóm các nhóm như vậy, thì một mảng của kiểu cấu trúc đó là đại diện tốt nhất. Người ta không nên sử dụng các cấu trúc có thể thay đổi ở những nơi mà người ta muốn một đối tượng, nhưng điều đó không có nghĩa là người ta nên sử dụng các đối tượng hoặc những thứ giả vờ là các đối tượng ở những nơi mà người ta muốn một loạt các biến bị mắc kẹt với băng keo.
supercat

Có một số tình huống mà bạn có thể muốn một cấu trúc có thể thay đổi, chẳng hạn như khi bạn cần một chút hiệu suất cuối cùng và không đủ khả năng phân bổ và tham chiếu heap, và trong trường hợp đó, một mảng các cấu trúc là đặt cược tốt nhất của bạn. Bài luận hay ở đây . Nhưng tôi không đồng ý rằng một lớp không nên đại diện cho "một loạt các biến bị mắc kẹt với nhau". Các cấu trúc và các lớp về mặt khái niệm hầu hết đều giống nhau, sự khác biệt chủ yếu là do các chi tiết thực hiện.
HugoRune

Nếu người ta muốn sử dụng một tập hợp các tham chiếu đối tượng có thể thay đổi như một tập hợp các nhóm biến độc lập, thì người ta phải thiết lập và duy trì một bất biến rằng mỗi phần tử xác định một đối tượng mà không có tham chiếu không phù hợp nào tồn tại ở bất kỳ đâu trong vũ trụ. Điều đó chắc chắn có thể được thực hiện (và thường là), nhưng không có gì trong ngôn ngữ hoặc khuôn khổ để hỗ trợ lập trình viên duy trì sự bất biến đó. Ngược lại, một mảng có độ dài 100 của một loại cấu trúc với bốn trường đối tượng sẽ tự động và đóng gói vĩnh viễn 400 biến độc lập.
supercat

Tôi nghĩ những bình luận này là nơi sai lầm để thảo luận thêm về vấn đề này và khi bạn thêm câu trả lời của riêng mình , dường như không cần phải sao chép thông tin này ở đây. Có thể nói, mảng có thể được sử dụng để quản lý các cấu trúc có thể thay đổi. Liệu và khi nào sử dụng hành vi thực hiện của các cấu trúc đó để thực thi các ràng buộc dữ liệu nhất định thực sự vượt quá phạm vi câu trả lời của tôi.
HugoRune

15

Vậy tại sao tôi lại muốn sử dụng một mảng?

Hiếm khi , bạn sẽ có một kịch bản mà bạn biết rằng bạn cần một số phần tử cố định. Từ quan điểm thiết kế, điều này nên tránh. Nếu bạn cần 3 thứ, bản chất của kinh doanh có nghĩa là bạn sẽ rất cần 4 thứ trong phiên bản tiếp theo.

Tuy nhiên, khi kịch bản hiếm gặp này thực sự xảy ra, sử dụng một mảng để thực thi bất biến kích thước cố định đó là hữu ích. Nó cung cấp một tín hiệu cho các lập trình viên khác rằng nó có kích thước cố định và giúp ngăn chặn việc sử dụng sai khi ai đó thêm hoặc xóa một phần tử - phá vỡ các kỳ vọng ở nơi khác trong mã.


23
Kích thước của các mảng không được đặt trong đá tại thời điểm người ta viết mã. Nó có thể, và thường là, một biến thời gian chạy. Nó chỉ không bao giờ thay đổi sau khi mảng đã được tạo .

11
Nó không phải là bất thường để đối phó với một số yếu tố cố định. Nếu bạn đang làm việc với các điểm 3D, có thể bạn sẽ không làm việc với các điểm 5D tại bất kỳ thời điểm nào trong tương lai. Vấn đề lớn hơn với mảng là chúng có thể thay đổi và không có nhãn thuận tiện gắn liền với các yếu tố của chúng.
Doval

3
@JanDvorak Danh sách có thể thu nhỏ hoặc tăng lên và do đó không có ý nghĩa trong bất kỳ bối cảnh nào liên quan đến một số yếu tố cố định.
Doval

9
Ít khi? Không phải tất cả mọi người làm việc trên các quái vật doanh nghiệp siêu cấu hình siêu phức tạp.
whatsisname

3
Nó là rất phổ biến để có một số yếu tố cố định. Chỉ cần đảm bảo độ dài được xác định bởi một hằng số, vì vậy khi phiên bản tiếp theo tăng số lượng phần tử từ 3 lên 4, bạn chỉ cần thay đổi hằng số và mọi thứ phụ thuộc vào điều này đều được điều chỉnh.
Hans

9

Câu hỏi của bạn đã thực sự được trả lời trước đó .

và dường như cũng hiệu quả trong bộ nhớ và hiệu suất như một mảng.

Không phải vậy. Từ câu hỏi tôi liên kết:

List/foreach:  3054ms (589725196)
Array/foreach: 1860ms (589725196)

Mảng nhanh gấp đôi trong một số trường hợp quan trọng. Tôi chắc chắn việc sử dụng bộ nhớ cũng khác nhau không tầm thường.

Vì tiền đề chính của câu hỏi của bạn đã bị đánh bại, tôi giả sử điều này trả lời câu hỏi của bạn. Ngoài ra, đôi khi các mảng bị ép buộc bởi API Win32 hoặc trình đổ bóng GPU của bạn hoặc một số thư viện không phải là DotNet khác.

Ngay cả trong DotNet, một số phương thức tiêu thụ và / hoặc trả về mảng (chẳng hạn như String.Split). Những phương tiện hoặc là bây giờ bạn phải ăn chi phí gọi ToListToArraytất cả thời gian, hoặc bạn phải phù hợp và mảng sử dụng, có thể tiếp tục chu kỳ bằng cách tuyên truyền này cho người dùng hạ lưu nghèo của bạn mã.

Thêm câu hỏi và câu trả lời về Stack Overflow về chủ đề này:


Điều thú vị, đó là câu trả lời điểm ra rằng nếu bạn sử dụng các vòng lặp được lập chỉ mục cũ ( cho thay vì foreach ) Sự khác biệt hiệu suất là tối thiểu.
dùng949300

3

Ngoài các lý do được liệt kê trong các câu trả lời khác, mảng bằng chữ cần ít ký tự hơn để khai báo:

var array = new [] { "A", "B", "C" };
var list = new List<string>() { "A", "B", "C" };

Sử dụng mảng thay vì Listlàm cho mã ngắn hơn một chút và chỉ dễ đọc hơn một chút trong trường hợp khi (1) bạn cần vượt qua bất kỳ IEnumerable<T>nghĩa đen nào , hoặc (2) khi chức năng khác Listkhông quan trọng và bạn cần sử dụng một số danh sách giống như nghĩa đen

Tôi đã làm điều này đôi khi trong các bài kiểm tra đơn vị.


1
Có chỉ để thêm. Bạn cũng cần phải vượt qua IList <T>
Esben Skov Pedersen

+1, tôi thường có một số thao tác cho một vài đối tượng cùng loại không có trong bộ sưu tập. Thật dễ dàng, ngắn gọn và rõ ràng để viết foreach( var x in new []{ a, b, c ) ) DoStuff( x )hoặc new []{ a, b, c ).Select( ... )vv
stijn

3

Đây là hoàn toàn từ quan điểm OO.

Trong khi tôi không thể nghĩ ra một lý do nào để chỉ vượt qua một mảng xung quanh, tôi chắc chắn có thể thấy các tình huống trong đó một đại diện mảng bên trong lớp có lẽ là lựa chọn tốt nhất.

Mặc dù có các tùy chọn khác cung cấp các đặc điểm tương tự, nhưng không có tùy chọn nào trực quan như một mảng cho các vấn đề xử lý hoán vị xử lý, lồng nhau cho các vòng lặp, biểu diễn ma trận, bitmap và thuật toán xen kẽ dữ liệu.

Có một số lượng đáng kể các lĩnh vực khoa học dựa trên toán học ma trận rộng rãi. (ví dụ: xử lý hình ảnh, sửa lỗi dữ liệu, xử lý tín hiệu số, một loạt các vấn đề toán học ứng dụng). Hầu hết các thuật toán trong các lĩnh vực đó được viết dưới dạng sử dụng các mảng / ma trận đa chiều. Vì vậy, sẽ là tự nhiên hơn khi thực hiện các thuật toán khi chúng được xác định thay vì làm cho chúng trở nên thân thiện với "phần mềm" hơn với chi phí mất các liên kết trực tiếp vào các bài báo mà thuật toán dựa trên.

Giống như tôi đã nói, trong những trường hợp này, bạn có thể thoát khỏi việc sử dụng danh sách nhưng điều đó lại thêm một lớp phức tạp khác lên trên các thuật toán vốn đã phức tạp.


3

Điều này thực sự phù hợp với các ngôn ngữ khác cũng có danh sách (như Java hoặc Visual Basic). Có những trường hợp bạn cần sử dụng một mảng vì một phương thức trả về một mảng thay vì Danh sách.

Trong một chương trình thực tế, tôi không nghĩ rằng một mảng sẽ được sử dụng rất thường xuyên, nhưng đôi khi bạn biết dữ liệu sẽ có kích thước cố định và bạn thích hiệu suất nhỏ mà bạn có được khi sử dụng một mảng. Tối ưu hóa vi mô sẽ là một lý do hợp lệ, giống như một phương thức trả về danh sách hoặc nhu cầu về cơ sở hạ tầng đa chiều.


1
Nhiều ngôn ngữ thậm chí không có bộ sưu tập danh sách và mảng riêng biệt. Mặt khác, sử dụng list<T>nơi vector<T>sẽ làm việc là một ý tưởng tồi tệ trong C / C ++.
Gort Robot

1
"Bởi vì một phương thức trả về một mảng" - đây là một lỗi sai của Java, buộc các lập trình viên phải viết mã bằng "Arrays.asList (x)". T [] ít nhất nên thực hiện Iterable <T>
kevin cline

4
@StevenBurnap - chắc chắn là rất tệ trong C, bởi vì không có cách nào để biên dịch mã đó.
Pete Becker

@PeteBecker Khái niệm vector<T> x biên dịch chỉ tốt cho tôi trong C . :-)
Svick

Xin lỗi, tôi có nghĩa là C cuộn tay tương đương với list<T>. Về cơ bản, tôi đã thấy rất nhiều vấn đề về hiệu năng do các nhà phát triển chỉ sử dụng danh sách theo mặc định khi một mảng là lựa chọn tốt hơn.
Gort Robot

1

Vâng, tôi đã tìm thấy một cách sử dụng cho các mảng trong một trò chơi tôi đã viết. Tôi đã sử dụng nó để tạo ra một hệ thống kiểm kê với số lượng vị trí cố định. Điều này có một số lợi ích:

  1. Tôi biết chính xác có bao nhiêu vị trí kho lưu trữ mở mà đối tượng trò chơi có bằng cách xem và xem vị trí nào là không.
  2. Tôi biết chính xác chỉ số của từng mục.
  3. Nó vẫn là một mảng "được gõ" (Mục [] Khoảng không quảng cáo), vì vậy tôi có thể thêm / xóa các đối tượng thuộc loại "Mục".

Tôi hình dung rằng nếu tôi cần "tăng" kích thước của kho, tôi có thể làm như vậy bằng cách chuyển các mục cũ sang mảng mới, nhưng vì kho được cố định bởi không gian màn hình và tôi không cần phải tự động làm cho nó lớn hơn / nhỏ hơn, nó hoạt động tốt cho mục đích tôi đang sử dụng.


1

Nếu bạn duyệt qua tất cả các thành phần của danh sách, thì không, một mảng là không cần thiết, 'tiếp theo' hoặc tùy ý 'lựa chọn mà không thay thế' sẽ hoạt động tốt.

Nhưng nếu thuật toán của bạn cần truy cập ngẫu nhiên vào các phần tử trong bộ sưu tập, thì, vâng, một mảng là cần thiết.

Điều này hơi giống với "có cần thiết không?". Trong một ngôn ngữ hiện đại hợp lý, nó không cần thiết chút nào. Nhưng nếu bạn bóc tách các khái niệm trừu tượng, tại một số điểm, đó là tất cả những gì thực sự có sẵn cho bạn, đó là cách duy nhất để thực hiện các trừu tượng này là với tính năng 'không cần thiết'. (Tất nhiên, sự tương tự không hoàn hảo, tôi không nghĩ có ai nói rằng mảng là thực hành lập trình kém; chúng dễ hiểu và dễ nghĩ).


Danh sách <T> cũng cung cấp quyền truy cập ngẫu nhiên. Chắc chắn, nó được triển khai với một mảng, nhưng điều đó không cần làm phiền bạn, người dùng. Vì vậy, tốt nhất, bạn đã đưa ra một lý do duy nhất để sử dụng mảng: Để thực hiện List<T>.

@delnan Tôi nghĩ đó là quan điểm của tôi đối với sự trừu tượng. Đôi khi tốt hơn là suy nghĩ về một mảng, không chỉ vì lý do hiệu quả. (tất nhiên đôi khi nó là cách tốt hơn để nghĩ về một danh sách liên kết, và cách tốt hơn so với suy nghĩ của một danh sách (mà không cần chăm sóc về các liên kết hoặc bằng cách khác như thế nào nó được thực hiện), và cách tốt hơn chỉ là một bộ sưu tập.
Mitch

0

Tương thích di sản.

Tất cả các hình thức kinh nghiệm cá nhân:

Lập trình viên kế thừa - đồng nghiệp của tôi sử dụng mảng ở khắp mọi nơi, đã thực hiện được hơn 30 năm, chúc may mắn thay đổi suy nghĩ của anh ấy với những ý tưởng mới mẻ của bạn.

Mã kế thừa - foo (thanh mảng []) chắc chắn bạn có thể sử dụng chức năng mã hóa danh sách / vector / bộ sưu tập nhưng nếu bạn không sử dụng bất kỳ tính năng bổ sung nào thì việc sử dụng một mảng sẽ dễ dàng hơn, thường dễ đọc hơn mà không cần chuyển đổi kiểu.

Sếp kế thừa - ông chủ của tôi là một lập trình viên giỏi trước khi cô ấy quản lý nhiều năm trước và vẫn nghĩ rằng cô ấy đã cập nhật, "đang sử dụng mảng" có thể kết thúc một cuộc họp, giải thích những gì một bộ sưu tập có thể khiến mọi người ăn trưa.


3
các đồng nghiệp chậm 20 năm và là một ông chủ muốn biết loại dữ liệu nào bạn đang sử dụng ... Tôi yêu trang này vì đã nhắc nhở bản thân rằng công việc của tôi có thể tồi tệ đến mức nào
JoelFan 10/12/14

1
khoảng 40% những gì chúng tôi làm là thiết kế nhúng trong đó các cuộc thảo luận được tổ chức bằng KB, anh ấy thích nói với tôi rằng anh ấy không lỗi thời, anh ấy đã nói rõ về lol
Skeith

0

1) Không có phiên bản Danh sách đa chiều. Nếu dữ liệu của bạn có nhiều chiều, việc sử dụng danh sách sẽ rất không hiệu quả.

2) Khi bạn đang xử lý một số lượng lớn các loại dữ liệu nhỏ (giả sử, bản đồ mà tất cả những gì bạn có là một byte cho loại địa hình) có thể có sự khác biệt đáng kể về hiệu suất do bộ đệm. Phiên bản mảng tải một số mục trên mỗi bộ nhớ đọc, phiên bản danh sách chỉ tải một mục. Hơn nữa, phiên bản mảng chứa số lượng ô trong bộ đệm nhiều lần so với phiên bản danh sách - nếu bạn liên tục xử lý dữ liệu, điều này có thể tạo ra sự khác biệt lớn nếu phiên bản mảng phù hợp với bộ đệm nhưng phiên bản danh sách thì không.

Đối với một trường hợp cực đoan, hãy xem xét Minecraft. (Vâng, nó không được viết bằng C #. Lý do tương tự cũng được áp dụng.)



0

Mảng 100 phần tử của một số loại T đóng gói 100 biến độc lập của loại T. Nếu T tình cờ là loại giá trị có trường công khai có thể thay đổi của loại Q và một loại R, thì mỗi phần tử của mảng sẽ đóng gói các biến độc lập do đó, kiểu Q và R. Toàn bộ mảng sẽ đóng gói 100 biến độc lập loại Q và 100 biến độc lập loại R; bất kỳ biến nào trong số đó có thể được truy cập riêng lẻ mà không ảnh hưởng đến bất kỳ biến nào khác. Không có loại bộ sưu tập nào ngoài mảng có thể cho phép các trường cấu trúc được sử dụng làm biến độc lập.

Thay vào đó, nếu T xảy ra là một loại lớp với các trường có thể thay đổi công khai của loại Q và R, thì mỗi phần tử của mảng giữ tham chiếu duy nhất , ở bất kỳ nơi nào trong vũ trụ T, và nếu không có phần tử nào của mảng sẽ được sửa đổi để xác định một đối tượng tồn tại bất kỳ tham chiếu bên ngoài nào, sau đó mảng sẽ đóng gói hiệu quả 100 biến độc lập loại Q và 100 biến độc lập loại R. Các loại bộ sưu tập khác có thể bắt chước hành vi của mảng đó, nhưng nếu mục đích duy nhất của mảng là để đóng gói 100 biến loại Q và 100 loại R, đóng gói từng cặp biến trong đối tượng lớp riêng của nó là một cách đắt tiền để làm điều đó. Thêm nữa,sử dụng một mảng hoặc tập hợp kiểu lớp có thể thay đổi sẽ tạo ra khả năng các biến được xác định bởi các phần tử mảng có thể không độc lập .

Nếu một loại được cho là hành xử giống như một loại đối tượng nào đó, thì nó phải là một loại lớp hoặc cấu trúc trường riêng không cung cấp phương tiện đột biến nào ngoài việc thay thế. Tuy nhiên, nếu một loại được cho là hoạt động giống như một loạt các biến độc lập có liên quan nhưng bị mắc kẹt với băng keo, thì ta nên sử dụng một loại một bó các biến được gắn với băng keo - một cấu trúc trường lộ . Mảng của các loại như vậy rất hiệu quả để làm việc và có ngữ nghĩa rất sạch sẽ. Sử dụng bất kỳ loại nào khác sẽ dẫn đến ngữ nghĩa sai lầm, hiệu suất kém hơn hoặc cả hai.


0

Một khác biệt quan trọng là phân bổ bộ nhớ. Ví dụ: việc duyệt qua danh sách được liên kết có thể dẫn đến nhiều lỗi bộ nhớ cache và hiệu năng chậm hơn, trong khi đó một mảng biểu thị một đoạn bộ nhớ liền kề chứa nhiều phiên bản của một số loại dữ liệu cụ thể và thực hiện theo dõi nó để có khả năng tấn công CPU bộ nhớ cache.

Tất nhiên, một loạt các tham chiếu đối tượng có thể không được hưởng lợi nhiều từ các lần truy cập bộ đệm, vì hội thảo sẽ vẫn đưa bạn đến bất cứ nơi nào trong bộ nhớ.

Sau đó, có các triển khai danh sách như ArrayList, thực hiện một danh sách bằng cách sử dụng một mảng. Chúng là những nguyên thủy hữu ích để có.


2
Câu hỏi đặc biệt hỏi về loại .Net List<T>, không được triển khai bằng cách sử dụng danh sách được liên kết, nhưng sử dụng một mảng (về cơ bản là tương đương với ArrayList<T>trong Java).
Svick

-2

Dưới đây là một số hướng dẫn bạn có thể sử dụng khi nào nên chọn Arrayvà khi nào nên chọn List.

  • Sử dụng Arraykhi trở về từ một phương thức.
  • Sử dụng Listlàm biến khi bạn đang xây dựng giá trị trả về (bên trong phương thức). Sau đó sử dụng .ToArray()khi trở về từ phương thức.

Nói chung, sử dụng Arraykhi bạn không có ý định cho người tiêu dùng thêm các mục vào bộ sưu tập. Sử dụng Listkhi bạn có ý định cho người tiêu dùng thêm các mặt hàng vào bộ sưu tập.

Arraycó nghĩa là để xử lý các bộ sưu tập "tĩnh" trong khi Listcó nghĩa là để xử lý các bộ sưu tập "động".


2
Quy tắc bạn đề xuất là tùy ý và có khả năng dẫn đến mã không hiệu quả thực hiện sao chép không cần thiết. Ít nhất bạn cần một số hình thức biện minh cho nó.
Jules

@Jules Tôi thấy trải nghiệm của nhà phát triển quan trọng hơn nhiều so với tối ưu hóa vi mô. Tôi không bao giờ có vấn đề về hiệu suất ở cấp độ này.
Daniel Lidström

Tuy nhiên, tôi không thấy trải nghiệm của nhà phát triển được cải thiện theo quy tắc này. Nó yêu cầu bạn phải đoán những khách hàng nào trong mã của bạn sẽ muốn làm gì với các giá trị được trả về và làm cho mã của bạn không thuận tiện để sử dụng khi bạn gặp lỗi, nhưng tôi không thấy bất kỳ lợi thế nào với nó. Hiệu suất có thể là mối quan tâm thứ yếu, nhưng tôi sẽ không hy sinh nó để tuân theo quy tắc không thu được gì.
Jules

@Jules Tôi đoán nó tùy thuộc vào sở thích của bạn rồi. Tôi thích coi giá trị trả về là hằng số, vì vậy tôi thích sử dụng Arraythay vì List. Rất vui được nghe những suy nghĩ của bạn!
Daniel Lidström

Bạn đã cân nhắc sử dụng UmmodifiableLists chưa?
Jules
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.