Массив в сравнении со списком <T>: когда и что использовать? - PullRequest
544 голосов
/ 12 января 2009
MyClass[] array;
List<MyClass> list;

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

Ответы [ 16 ]

528 голосов
/ 12 января 2009

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

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

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

Смотри также:

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

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

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

114 голосов
/ 12 января 2009

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

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

45 голосов
/ 12 января 2009

Используйте массив при работе с данными:

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

Использовать список для:

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

Использовать хэш-карту для:

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

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

18 голосов
/ 12 января 2009

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

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

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

6 голосов
/ 05 марта 2015

Массивы следует использовать вместо предпочтения 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');

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

3 голосов
/ 23 ноября 2009

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

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

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

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

3 голосов
/ 12 января 2009

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

1 голос
/ 27 февраля 2018

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

Итак, если вы пишете метод, который принимает List<MyClass> в качестве аргумента, но использует только подмножество функций, вы можете объявить вместо него IList<MyClass> для удобства вызывающих.

подробности:

1 голос
/ 09 июля 2017

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...