Array versus List <T>: когда использовать какой?

MyClass[] array;
List<MyClass> list;

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

Ответы

Ответ 1

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

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

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

См. также:

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

Массивы должны использоваться в предпочтении 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, которое нарушает подход Design by Contract. В случае String это не имеет большого значения, но это может быть большой проблемой практически во всех других случаях. Настройка списка только для чтения помогает, но приводит к ошибкам во время выполнения, а не компиляции.

Ответ 7

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

Ответ 8

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

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

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

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

Поскольку никто не упоминает: в С# массив представляет собой список. 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> вместо этого для удобства вызывающих.

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

Ответ 12

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

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

Ответ 13

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

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

Ответ 14

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

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

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

Ответ 15

Заполнить список проще, чем массив. Для массивов вам нужно знать точную длину данных, но для списков размер данных может быть любым. И вы можете преобразовать список в массив.

List<URLDTO> urls = new List<URLDTO>();

urls.Add(new URLDTO() {
    key = "wiki",
    url = "https://...",
});

urls.Add(new URLDTO()
{
    key = "url",
    url = "http://...",
});

urls.Add(new URLDTO()
{
    key = "dir",
    url = "https://...",
});

// convert a list into an array: URLDTO[]
return urls.ToArray();

Ответ 16

Массивы Vs. Списки - это классическая проблема удобства обслуживания и производительности. Практическое правило, которому следуют почти все разработчики, заключается в том, что вы должны использовать оба подхода, но когда они вступают в конфликт, выбирайте удобство обслуживания вместо производительности. Исключением из этого правила является ситуация, когда производительность уже оказалась проблемой. Если вы несете этот принцип в Arrays Vs. Списки, то, что вы получите, это:

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