От новичка до гуру: Курсы программирования на CyberDuff

Должен ли я всегда использовать TList‹String› вместо Array of String?

Я переносил проект, разработанный в Delphi 7, и просматривал код каждый раз, когда предыдущие разработчики хотели использовать коллекцию, которую они создали примерно так:

ArrayOfString : array of string;
ArrayOfInteger: array of integer;
ArrayOfStringArrays : array of ArrayOfString;

Этот вид кода повторяется во многих местах, а также «SetLength» для каждого из них несколько раз, интересно, изменим ли все это Array of Something на TList<Something> сейчас, когда мы находимся в Delphi XE4.

Есть ли в этом какое-то преимущество, ресурс, скорость или что-то в этом роде, чтобы поддержать меня в этом решении?

PS: я родом из JAVA, и Delphi мне кажется темным и полным ужасов

17.06.2014

  • Тогда добро пожаловать во тьму и ужас! :) 18.06.2014

Ответы:


1

Думайте о динамическом массиве как о конструкции более низкого уровня, чем TStringList или TList<T>.

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

Классы коллекций более высокого уровня, TStringList и TList<T>, построены поверх динамических массивов. Вот как хранится содержимое внутри. Но классы коллекций завершают это за вас. Операции более высокого уровня, такие как вставка и удаление и многие другие, предоставляются в виде методов. По сути, эти классы коллекций обеспечивают гораздо больше удобства, чем необработанные динамические массивы.

Для иллюстрации рассмотрим действие вставки элемента. Для динамического массива вы должны сделать это:

  1. Измените размер массива.
  2. Переместите элементы, которые находятся после точки вставки, из позиции i в позицию i+1.
  3. Назначить вставленный элемент.

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

Для коллекции высокого уровня вы пишете:

List.Insert(Index, Value);

и пусть класс позаботится о деталях.

Обратите внимание, что по историческим причинам, а также потому, что строки особенно важны, разработчики, как правило, используют специально выделенный класс TStringList, а не TList<string>. Опять же, выделенный класс предлагает функциональные возможности помимо TList<string>, поскольку он специализируется на строках и может предлагать функциональные возможности, предназначенные для строк. Опять же, специальный класс предлагает удобство.

Одно из мест, где динамические массивы пригодятся, — это когда вы не хотите брать на себя шаблон управления жизненным циклом. Таким образом, для настольных компиляторов, у которых нет ARC для классов, вам необходимо явно уничтожить TList<T> экземпляров. Но у динамических массивов время жизни управляется ARC. Если вы синтезируете массивы за один раз, а затем не изменяете их размер, то проблема управления временем жизни может сделать массивы более удобными в использовании.

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

17.06.2014
  • Я бы не стал задавать новый вопрос по этому поводу, но есть проект, в котором все делается с помощью динамических массивов, мне интересно, стоит ли заменить их для TList‹T› или оставить все как есть... не могли бы вы мне посоветовать ? 18.07.2014
  • Невозможно сказать отсюда 18.07.2014

  • 2

    Во-первых, в новых версиях Delphi есть тип TArray<T>, который можно использовать для замены всех этих старых объявлений array of whatever. Его использование может обойти некоторые давние ошибки в языке, оставшиеся от классического Паскаля, и помочь вам не столкнуться с запутанными ошибками в будущем.

    Сказав это, TStringList не является строковым массивом; это объект-контейнер, содержащий список строк. Он имеет несколько специализированных методов для обработки списков строк, что делает его чрезвычайно универсальным: его можно использовать как список строк, набор строк (через свойство .Sorted), карту строк/объектов (через свойство .Objects) и карта строка/строка (через свойства .Names и .Values).

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

    for i := 0 to Count - 1 do
    begin
       SetLength(myArray, length(myArray) + 1);
       myArray[high(myArray)] := values[i];
    end;
    

    С общим TList<T> или TStringList это становится:

    for i := 0 to Count - 1 do
    begin
       myList.Add(values[i]);
    end;
    

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

    Однако следует помнить одну вещь: если вы работаете с Java, имейте в виду, что динамические массивы — это типы, управляемые компилятором, а классы списков — это объекты, которые необходимо освобождать в коде.

    17.06.2014
  • ... и значительно более производительный, так что это правда, что списки обрабатываются быстрее, чем массивы? 18.06.2014
  • @sandiego206: я специально имел в виду, что добавление всех этих элементов в список будет значительно более эффективным, чем необходимость вызывать SetLength снова и снова. Что касается обработки вещей, это действительно зависит от того, что именно вы подразумеваете под обработкой. 18.06.2014
  • для первого примера перемещение SetLength(myArray, length(myArray) + Count); за пределы цикла будет более эффективным, так как выделение кучи будет выполнено только один раз. Для TStrings и потомков используйте myList.Capacity := myList.Capacity + Count, чтобы сделать то же самое (в более поздних версиях Delphi SetCapacity вызывает SetLength для внутреннего массива) 18.06.2014
  • Динамические массивы @sandiego обеспечат наилучшую производительность при условии, что вы позаботитесь о минимизации перераспределений. Однако я не вижу доказательств того, что производительность является вашей главной проблемой. Это? 18.06.2014
  • @Mason В терминах CS то, что Delphi называет списком, на самом деле является массивом. Коллекция однородных типизированных элементов, индексированных непрерывным диапазоном целых чисел. В терминах CS список означает связанный список в той или иной форме. Терминология, выбранная Эмбой, в лучшем случае неудачна. Список Delphi имеет характеристики производительности массива. 18.06.2014
  • @DavidHeffernan Что такое термины Counter Strike? 18.06.2014
  • @PageNotFound Информатика 18.06.2014

  • 3

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

    Доступ к TStringList можно получить как к массиву через myStringList.Items[i] или даже просто через myStringList[i].

    Вам не нужно постоянно изменять длину или вести подсчет, вы просто myStringList.Add(aString) и myStringList.Count (не забудьте -1 для цикла).

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

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

    Надеюсь это поможет.

    18.06.2014
  • А если вы хотите коллекцию вещей, которые не являются строками? 18.06.2014
  • ЕСЛИ вы хотите иметь коллекцию объектов, то TObjectList‹T› — это инструмент для этой работы. У него есть все плюсы, которые есть у TStringList, кроме объектов. Если вам действительно нужно использовать массив, то ладно, но если вам нужна коллекция, тогда TObjectList‹T› для объектов и TStringList для строк. 18.06.2014
  • Вы используете TObjectList<T> только тогда, когда вам нужен список для владения объектами. В противном случае TList<T> лучше. Но как насчет набора целых чисел, согласно вопросу? 18.06.2014
  • Я не видел массив целых чисел в исходном вопросе.. упс. Я создал собственный класс List для целых чисел, массивов или потомков TList, которые можно использовать для обеспечения функциональности. Использование потомка TList обеспечивает все преимущества TList, о которых я упоминал выше. TObjectList.Create(False) гарантирует, что список объектов не владеет объектами для уничтожения. Я не понимаю, почему TList лучше. TObjectList и TObjectList‹T› являются производными от TList и TList‹T›, но предоставляют некоторые дополнительные функциональные возможности. 19.06.2014
  • Забудьте о неуниверсальных версиях. Никто не собирается писать новый код, используя их. Дополнительная функциональность, которую предоставляет TObject<T>, — это владение объектом. Если вы этого не хотите, не берите. 19.06.2014
  • Новые материалы

    5 простых концепций Python, ставших сложными
    #заранее извините 1) Переменные x = 4 y = 5 Переменная в Python — это символическое представление объекта. После присвоения некоторого объекта переменной Python мы приобретаем..

    «Освоение вероятности: изучение совместной, предельной, условной вероятности и теоремы Байеса —…
    Виды вероятности: Совместная вероятность Предельная вероятность Условная вероятность Диаграмма Венна в вероятностях: В “Set Theory” мы создаем диаграмму Венна...

    Основы Spring: Bean-компоненты, контейнер и внедрение зависимостей
    Как лего может помочь нашему пониманию Когда мы начинаем использовать Spring, нам бросают много терминов, и может быть трудно понять, что они все означают. Итак, мы разберем основы и будем..

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

    Я предполагаю, что вы имеете в виду методы обработки категориальных данных.
    Я предполагаю, что вы имеете в виду методы обработки категориальных данных. Пожалуйста, проверьте мой пост Инструментарий специалиста по данным для кодирования категориальных переменных в..

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

    «Раскрытие математических рассуждений с помощью Microsoft MathPrompter и моделей больших языков»
    TL;DR: MathPrompter от Microsoft показывает, как использовать математические рассуждения с большими языковыми моделями; 4-этапный процесс для улучшения доверия и рассуждений в математических..