Array versus List: когда использовать что?

MyClass[] array;
List<MyClass> list;

какие сценарии, когда один предпочтительнее другого? И почему?

14 ответов


редко, на самом деле, что вы хотели бы использовать массив. Определенно используйте List<T> в любое время, когда вы хотите добавить/удалить данные, так как изменение размера массивов дорого. Если вы знаете, что данные фиксированной длины, и вы хотите микро-оптимизировать для некоторых очень специфический причина (после тестирования), то массив может быть полезен.

List<T> предлагает много больше функциональности, чем массив (хотя LINQ выравнивает его немного), и почти всегда является правильным выбор. Кроме params аргументы, конечно. - p

как счетчик -List<T> является одномерным; где-как у вас есть прямоугольные (etc) массивы, такие как int[,] или string[,,] - но есть и другие способы моделирования таких данных (если необходимо) в объектную модель.

Читайте также:

что сказал, я делаю много использования массивов в my protobuf-чистая проект; полностью для производительности:

  • он делает много бит-сдвига, так что byte[] в значительной степени важно для кодирования;
  • я использую местную прокатку byte[] буфер, который я заполняю перед отправкой в базовый поток (и v. v.); быстрее, чем BufferedStream и т. д.;
  • он внутренне использует модель объектов на основе массива (Foo[], а не List<Foo>), поскольку размер фиксируется после сборки, и должен быть очень быстрым.

но это, безусловно, исключение; для общей линии обработки бизнеса,List<T> выигрывает каждый раз.


действительно просто отвечая, чтобы добавить ссылку, о которой я удивлен, еще не упоминалось: запись блога Эрика Липперта на "массивы считаются чем-то вредным."

вы можете судить по названию, что он предлагает использовать коллекции везде, где это практично, но, как справедливо отмечает Марк, есть много мест, где массив действительно является единственным практическим решением.


использовать массив, когда вы имеете дело с данными, то есть:

  • фиксированный размер, или вряд ли вырастет много
  • подходяще большие (более 10, 50, 100 элементов, в зависимости от алгоритма)
  • вы будете делать много индексирования в него, то есть вы знаете, что часто хотите третий элемент, или пятый, или что-то еще.

используйте список для:

  • списки данных переменной длины
  • , которые в основном используются в качестве стек или очередь или должны быть повторены в полном объеме
  • когда вы не хотите писать выражение для получения конечного размера массива для объявления, и вы не хотите расточительно выбирать большое число

используйте hashmap для:

  • списки данных переменной длины
  • которые должны быть индексированы как массив

на самом деле вам понадобится список или hashmap почти все время. В следующий раз, когда вы выберете данные структура, подумайте о том, что она должна делать хорошо для вас (или вашего кода, во всяком случае). Тогда выбери что-нибудь на основе этого. Когда сомневаетесь, выберите что-то как можно более общее, т. е. интерфейс, который вы можете заменить реализацией довольно легко. Некоторые хорошие ссылки в других ответах также.


несмотря на другие ответы, рекомендовать List<T>, вы захотите использовать массивы при обработке:

  • изображения растровые данные
  • другие низкоуровневые структуры данных (т. е. сетевые протоколы)

Если вы действительно не заинтересованы в производительности, и под этим я подразумеваю: "почему вы используете .Net вместо C++?"вы должны придерживаться списка. Это легче поддерживать и делает всю грязную работу по изменению размера массива за кулисами для вас. (При необходимости List довольно умен в выборе размеров массива, поэтому обычно это не требуется.)


массивы должны предпочтительно использовать список, когда неизменяемость самой коллекции является частью контракта между кодом клиента и поставщика (не обязательно неизменяемость элементов в коллекции) и когда IEnumerable не подходит.

например,

var str = "This is a string";
var strChars = str.ToCharArray();  // returns array

ясно, что модификация " strChars "не будет мутировать исходный объект" str", независимо от уровня реализации знаний о "STR", лежащих в основе тип.

но предположим, что

var str = "This is a string";
var strChars = str.ToCharList();  // returns List<char>
strChars.Insert(0, 'X');

в этом случае из этого фрагмента кода не ясно, будет ли метод insert мутировать исходный объект " str " или нет. Для этого требуется знание уровня реализации строки, чтобы сделать это определение, которое нарушает дизайн контрактным подходом. В случае String это не имеет большого значения, но это может быть большое дело почти в каждом другом случае. Установка списка только для чтения помогает, Но приводит к ошибкам во время выполнения, а не во время компиляции.


Если я точно знаю, сколько элементов мне понадобится, скажем, мне нужно 5 элементов и только когда-нибудь 5 элементов, затем я использую массив. В противном случае я просто использую List.


большую часть времени, используя List хватило бы. А List использует внутренний массив для обработки данных, и автоматически изменяет размер массива при добавлении элемента List чем его текущая емкость, что делает его более простым в использовании, чем массив, где вам нужно знать емкость заранее.

см http://msdn.microsoft.com/en-us/library/ms379570(v=vs. 80).aspx#datastructures20_1_topic5 для получения дополнительной информации о списках в C# или просто декомпилировать System.Collections.Generic.List<T>.

Если вам нужны многомерные данные (например, с помощью матрицы или в графическом программировании), вы, вероятно, пойдете с .

как всегда, если проблема с памятью или производительностью, измерьте ее! В противном случае вы можете делать ложные предположения о коде.


другая ситуация, еще не упомянутая, когда у вас будет большое количество элементов, каждый из которых состоит из фиксированной связки связанных, но независимых переменных, склеенных вместе (например, координаты точки или вершины 3d-треугольника). Массив структур открытого поля позволит эффективно изменять его элементы "на месте" - то, что невозможно с любым другим типом коллекции. Поскольку массив структур последовательно удерживает свои элементы в ОЗУ, последовательный доступ к элементам массива может быть очень быстро. В ситуациях, когда коду нужно будет сделать много последовательных проходов через массив, массив структур может превзойти массив или другую коллекцию ссылок на объекты класса в 2:1; Кроме того, возможность обновления элементов на месте может позволить массиву структур превзойти любой другой вид коллекции структур.

хотя массивы не изменяются, нетрудно иметь код для хранения массива ссылка вместе с количеством элементов, которые используются, и замените массив на больший по мере необходимости. Кроме того, можно легко написать код для типа, который ведет себя как List<T> но выставил свой резервный магазин, тем самым позволяя сказать либо MyPoints.Add(nextPoint); или MyPoints.Items[23].X += 5;. Обратите внимание, что последний не обязательно выдаст исключение, если код попытается получить доступ за пределы конца списка, но использование в противном случае будет концептуально очень похоже на List<T>.


списки в .NET являются оболочками над массивами и используют массив внутри. Временная сложность операций над списками такая же, как и с массивами, однако есть немного больше накладных расходов со всеми дополнительными функциями / простотой использования списков (например, автоматическое изменение размера и методы, которые поставляются с классом list). В значительной степени, я бы рекомендовал использовать списки во всех случаях, если нет веской причины не для этого, например, если вам нужно написать чрезвычайно оптимизированный код, или работают с другим кодом, который построен вокруг массивов.


это полностью зависит от контекстов, в которых необходима структура данных. Например, если вы создаете элементы для использования другими функциями или службами с помощью List, это идеальный способ сделать это.

теперь, если у вас есть список элементов, и вы просто хотите их отобразить, скажем, на веб-странице массив-это контейнер, который вам нужно использовать.


вместо того, чтобы проходить сравнение функций каждого типа данных, я думаю, что самый прагматичный ответ: "различия, вероятно, не так важны для того, что вам нужно выполнить, тем более, что они оба реализуют IEnumerable, поэтому следуйте популярной конвенции и используйте List пока у вас нет причины не делать этого, и в этот момент у вас, вероятно, будет причина использовать массив над List."

большую часть времени в управляемом коде вы захотите использовать коллекции, как легко работать с как можно более беспокоясь о микро-оптимизации.


Они могут быть непопулярны, но я поклонник массивов в игровых проектах. - Скорость итерации может быть важна в некоторых случаях, foreach на массиве имеет значительно меньше накладных расходов, если вы не делаете много на элемент - Добавление и удаление не так сложно с вспомогательными функциями - Его медленнее, но в случаях, когда вы только строите его один раз, это может не иметь значения - В большинстве случаев тратится меньше дополнительной памяти (только действительно значительные массивы структур) - Немного меньше мусора и указателей и указателя погоня!--1-->

Это, как говорится, Я использую список гораздо чаще, чем массивы на практике, но у каждого из них есть свое место.

было бы неплохо, если бы список, где встроенный тип, чтобы они могли оптимизировать накладные расходы оболочки и перечисления.


так как никто не упоминал: MyClass[] и List<MyClass> как реализовать IList<MyClass>. Если вы размышляете, какой из них принять в качестве аргумента, вы можете объявить его как IList<MyClass> для удобства абонентов. (например,Foo(IList<int> foo) можно назвать как Foo(new[] { 1, 2, 3 }) или Foo(new List<int> { 1, 2, 3 }) )