Общий список записей с подсписком?

Я хочу использовать общий TList записей с подсписком в Delphi XE5:

type
  TMyRecord=record
    Value1: Real;
    SubList: TList<Integer>;
  end;

  TMyListOfRecords=TList<TMyRecord>;

var
  MyListOfRecords: TMyListOfRecords;

Назначения в поле записей не возможны:

MyListOfRecords[0].Value1:=2.24; 

или же

MyListOfRecords[0].SubList:=TList<Integer>.Create;

приведет к ошибке "левая сторона не может быть назначена" компилятором.

Смотрите также: Как изменить значение TList?

Следующий обходной путь работает:

AMyRecord:=MyListOfRecords[0];
AMyRecord.Value1:=2.24;
AMyRecord.SubList:=TList<Integer>.Create;
AMyRecord.SubList.Add(33);
MyListOfRecords[0]:=AMyRecord;

Из-за проблем с производительностью я хотел бы избежать копирования данных во временную запись AMyrecord. Я бы предпочел получить доступ к полям записи и подсписку напрямую.

Каков наилучший способ справиться с этим?

1 ответ

Решение

Список предоставляет свое внутреннее хранилище, которое представляет собой динамический массив, через List имущество. Таким образом, вы можете написать:

MyListOfRecords.List[0].Value1 := 2.24; 

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

Как правильно говорит @LURD, List возвращает внутреннее хранилище. И это может иметь больше, чем Count элементы. Конкретно это имеет Capacity элементы. Таким образом, если вы используете его, вы должны получить доступ к элементам с помощью индексации массива поверх элементов 0 в Count-1, Помните также, что изменения размера списка могут включать перераспределение, и поэтому внутреннее хранилище может перемещаться. Любая ссылка на которую вы берете List действует только до следующего перераспределения.

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

В моей кодовой базе у меня есть альтернатива TList<T> чья Items[] Свойство возвращает указатель на элемент. Контейнер по-прежнему хранится в виде динамического массива для эффективного размещения памяти. Я предпочел этот вариант List собственность, потому что я чувствовал, что это привело к более чистому коду.


Хорошо, вы попросили взглянуть на мой класс списка, который возвращает указатели на элементы. Вот:

type
  TReferenceList<T> = class(TBaseValueList<T>)
  type
    P = ^T;
  private
    function GetItem(Index: Integer): P;
  public
    property Items[Index: Integer]: P read GetItem; default;
  public
    // .... helper types for enumerators excised
  public
    function GetEnumerator: TEnumerator;
    function Enumerator(Forwards: Boolean): TEnumeratorFactory;
    function ReverseEnumerator: TEnumeratorFactory;
    function IndexedEnumerator: TIndexedEnumeratorFactory;
  end;

Теперь нужно какое-то объяснение. Базовый класс, TBaseValueList<T> моя альтернатива TList<T>, Вы могли бы заменить TList<T> если хочешь. Я не знаю, потому что мой базовый класс не имеет Items имущество. Это потому, что я хочу, чтобы специализированные классы представили это. Моя другая специализация:

type
  TValueList<T> = class(TBaseValueList<T>)
  private
    function GetItem(Index: Integer): T;
    procedure SetItem(Index: Integer; const Value: T);
  public
    property Items[Index: Integer]: T read GetItem write SetItem; default;
  end;

Реализация моего TBaseValueList<T> довольно очевидно. Это очень похоже на TList<T>, Я не думаю, что вам действительно нужно видеть какую-либо реализацию. Это все очень очевидно.

Как простой способ получить ссылку на элемент, вы можете обернуть List так:

type
  TMyList<T> = class(TList<T>)
  public
    type
      P = ^T;
  private
    function GetRef(Index: Integer): P;
  public
    property Ref[Index: Integer]: P read GetRef;
  end;

function TMyList<T>.GetRef(Index: Integer): P;
begin
  Result := @List[Index];
end;

Если вам нужен более богатый набор контейнеров, чем в Delphi, вам стоит взглянуть на Spring4D. Хотя я не уверен, есть ли у них что-то вроде моего контейнера, который возвращает ссылки.

Другие вопросы по тегам