.NET предлагает общий контейнер списков, производительность которого практически идентична (см. Вопрос «Производительность массивов и списков»). Однако они совершенно разные по инициализации.
Массивы очень легко инициализировать со значением по умолчанию, и по определению они уже имеют определенный размер:
string[] Ar = new string[10];
Это позволяет безопасно назначать случайные элементы, например:
Ar[5]="hello";
со списком все сложнее. Я вижу два способа выполнить одну и ту же инициализацию, ни один из которых нельзя назвать элегантным:
List<string> L = new List<string>(10);
for (int i=0;i<10;i++) L.Add(null);
или
string[] Ar = new string[10];
List<string> L = new List<string>(Ar);
Что было бы чище?
РЕДАКТИРОВАТЬ: ответы пока относятся к емкости, которая представляет собой нечто иное, чем предварительное заполнение списка. Например, в только что созданном списке с емкостью 10 нельзя сделатьL[2]="somevalue"
РЕДАКТИРОВАТЬ 2: Люди задаются вопросом, почему я хочу использовать списки таким образом, поскольку они не предназначены для использования. Я вижу две причины:
Можно довольно убедительно утверждать, что списки - это массивы «следующего поколения», добавляющие гибкости практически без потерь. Поэтому их следует использовать по умолчанию. Я указываю, что их может быть не так просто инициализировать.
В настоящее время я пишу базовый класс, предлагающий функции по умолчанию как часть более крупной структуры. В предлагаемой мной функциональности по умолчанию размер списка известен заранее, поэтому я мог бы использовать массив. Однако я хочу предложить любому базовому классу возможность динамически расширять его, поэтому я выбираю список.
List
не заменяетArray
. Они решают совершенно разные задачи. Если вам нужен фиксированный размер, вам нужен файлArray
. Если вы используете aList
, вы делаете это неправильно.Ответы:
Не могу сказать, что мне это нужно очень часто - не могли бы вы подробнее рассказать, зачем вам это нужно? Я бы, наверное, поместил это как статический метод во вспомогательный класс:
Вы можете использовать,
Enumerable.Repeat(default(T), count).ToList()
но это будет неэффективно из-за изменения размера буфера.Обратите внимание, что если
T
это ссылочный тип, он будет хранитьcount
копии ссылки, переданной дляvalue
параметра, поэтому все они будут ссылаться на один и тот же объект. Это может быть или не быть тем, что вы хотите, в зависимости от вашего варианта использования.РЕДАКТИРОВАТЬ: как отмечено в комментариях, вы можете
Repeated
использовать цикл для заполнения списка, если хотите. Это тоже было бы немного быстрее. Лично я считаю, что кодRepeat
более нагляден, и подозреваю, что в реальном мире разница в производительности не имеет значения, но ваш опыт может отличаться.источник
Enumerable.Repeat(...).ToArray()
, а я его не использую.Enumerable.Repeat()
следующим образом (реализовано такPair
же, как эквивалент C ++):Enumerable.Repeat( new Pair<int,int>(int.MaxValue,-1), costs.Count)
заметил побочный эффект, что онList
был заполнен ссылочными копиями для одного объекта. Изменение элемента, например,myList[i].First = 1
изменило каждый элемент в целомList
. Мне потребовались часы, чтобы найти эту ошибку. Вы, ребята, знаете какое-нибудь решение этой проблемы (кроме простого использования общего цикла и использования.Add(new Pair...)
?источник
L
просто повторно использовать памятьstring[10]
как есть (резервное хранилище списков также является массивом) или он будет выделять новую собственную память, а затем копировать содержимоеstring[10]
?string[10]
автоматически соберет мусор, еслиL
выберет более поздний маршрут.Используйте конструктор, который принимает в качестве аргумента int ("емкость"):
РЕДАКТИРОВАТЬ: Я должен добавить, что согласен с Фредериком. Вы используете Список таким образом, который, в первую очередь, идет вразрез со всей логикой его использования.
РЕДАКТИРОВАТЬ2:
Зачем кому-то нужно знать размер списка со всеми нулевыми значениями? Если в списке нет реальных значений, я ожидаю, что длина будет равна 0. В любом случае, тот факт, что это неаккуратно, демонстрирует, что это идет вразрез с предполагаемым использованием класса.
источник
new List<string>()
чем проблема. . Молодец, получив столько голосов за :)list[index] = obj;
и использовать некоторые другие возможности списка.Сначала создайте массив с нужным количеством элементов, а затем преобразуйте его в список.
источник
Почему вы используете список, если хотите инициализировать его фиксированным значением? Я могу понять, что - ради производительности - вы хотите дать ему начальную емкость, но разве не одно из преимуществ списка перед обычным массивом в том, что он может увеличиваться при необходимости?
Когда вы это сделаете:
Вы создаете список, содержащий 100 целых чисел. Это означает, что вашему списку не нужно будет «расти», пока вы не добавите 101-й элемент. Базовый массив списка будет инициализирован длиной 100.
источник
Инициализация содержимого такого списка не совсем то, для чего нужны списки. Списки предназначены для хранения объектов. Если вы хотите сопоставить определенные числа с конкретными объектами, рассмотрите возможность использования структуры пары ключ-значение, такой как хеш-таблица или словарь, вместо списка.
источник
Кажется, вы подчеркиваете необходимость позиционной связи с вашими данными, поэтому не будет ли ассоциативный массив более подходящим?
источник
Если вы хотите инициализировать список N элементами некоторого фиксированного значения:
источник
Вы можете использовать Linq, чтобы грамотно инициализировать свой список значением по умолчанию. (Подобно ответу Дэвида Б. )
Сделайте еще один шаг и инициализируйте каждую строку отдельными значениями «строка 1», «строка 2», «строка 3» и т. Д.:
источник
источник
В принятом ответе (с зеленой галочкой) есть проблема.
Эта проблема:
Я рекомендую изменить строку выше, чтобы выполнить копию объекта. Об этом написано много разных статей:
Если вы хотите инициализировать каждый элемент в своем списке конструктором по умолчанию, а не NULL, добавьте следующий метод:
источник
Замечание о IList: MSDN IList Замечания : «Реализации IList делятся на три категории: только для чтения, фиксированного размера и переменного размера. (...). Для общей версии этого интерфейса см.
System.Collections.Generic.IList<T>
."IList<T>
НЕ наследуется отIList
(ноList<T>
реализует обаIList<T>
иIList
), но всегда имеет переменный размер . Начиная с .NET 4.5, у нас также есть,IReadOnlyList<T>
но AFAIK, нет общего списка фиксированного размера, который был бы тем, что вы ищете.источник
Это образец, который я использовал для своего модульного теста. Я создал список объектов класса. Затем я использовал forloop, чтобы добавить X объектов, которые я ожидаю от службы. Таким образом, вы можете добавить / инициализировать список любого заданного размера.
Надеюсь, я помог вам, ребята.
источник
Немного поздно, но первое предложенное вами решение кажется мне намного чище: вы не выделяете память дважды. Даже конструктору List необходимо пройти через массив, чтобы скопировать его; он даже заранее не знает, что внутри есть только нулевые элементы.
1. - выделить N - цикл N Стоимость: 1 * выделить (N) + N * loop_iteration
2. - выделить N - выделить N + loop () Стоимость: 2 * выделить (N) + N * loop_iteration
Однако распределение циклов в List может быть быстрее, так как List является встроенным классом, но C # скомпилирован jit sooo ...
источник