Delphi TList<T> Копировать в другой TList?
Я хотел бы знать, есть ли какой-либо безопасный способ скопировать элементы TList в любой другой TList в определенную позицию и с определенной длиной. Должен ли я просто назначить элементы list1 для list2 или есть какая-то функциональность, я не знаю, что обрабатывает это более точно?
Спасибо, что нашли время.
3 ответа
Если вы намереваетесь ЗАМЕНИТЬ элементы вместо того, чтобы вставлять их в заданную позицию, то ответ заключается в том, что прямого механизма не существует, и итеративное назначение является подходом для использования.
for i := 1 to maxItems do
dest[ insertPos + i - 1] := src[ i - 1 ];
В этом случае вы должны рассмотреть ситуацию, когда вы добавляете больше элементов, чем в списке мест назначения. Означает ли это, что нужно заменить только то количество элементов, которое "уместится", добавить дополнительные элементы в "освободить место" или не назначить их вообще (если не все), - вопрос, на который могут ответить только ваши требования.
Однако, если вы хотите вставить элементы в список назначения, вы можете использовать комбинацию InsertRange() и Copy() вместе с внутренним массивом
var
src, dest: TList<String>;
insertIndex, maxItems: Integer;
dest.InsertRange( insertIndex, Copy( src.List, 0, maxItems ) );
Для вставки всего списка src вам не нужно использовать Copy(), но вы можете ссылаться на исходный список непосредственно в методе InsertRange():
dest.InsertRange( insertIndex, src );
Примечания по производительности:
Использование Copy() является потенциально дорогой операцией, если список источников велик и / или количество добавляемых подпунктов невелико. Однако фактическая вставка элементов в список адресатов очень эффективна, поскольку метод InsertRange() может освободить место для новых элементов в списке адресатов за одну операцию, а затем вставить новые элементы в пространство, созданное для них. Таким образом, для большего количества добавляемых предметов он все же может оказаться наиболее эффективным.
Альтернативный подход заключается в итеративной вставке исходных элементов по отдельности:
for i := 1 to maxItems do
dest.Insert( insertIndex, src[i - 1]);
Хотя это позволяет избежать копирования вставляемых элементов массива, итеративная вставка сама по себе потенциально неэффективна, если список адресатов большой и вставляется большее количество элементов, поскольку место для каждого элемента в списке адресатов должно быть выделено отдельно для каждой вставки (хотя потенциальное влияние этого может быть значительно улучшено за счет явного вычисления и предварительного распределения емкости списка адресатов).
например, если вы вставляете 100 элементов из списка 1000 элементов в (точную) середину списка 2000 элементов:
InsertRange( Copy() ) Copy 100 items into an intermediate array
Moves 1000 items in the dest list to make room for 2100 (total)
Inserts 100 items into the 'blank' space
Iterative insert 100 repetitions of:
Move 1000 items in the dest list to make room for 1 more
Inserts 1 item
Для вставки 100 элементов InsertRange() потенциально наиболее эффективен. В отличие от этого, если вставить только один элемент из списка источников, то подход InsertRange() влечет за собой чрезмерные издержки.
Как я думаю, должно быть очевидно, что различные начальные условия будут определять, какой из двух подходов является наиболее эффективным, и его следует учитывать, если производительность является серьезной проблемой.
Я бы использовал AddRange для добавления элементов в конец или InsertRange для вставки элементов по определенному индексу.
В дополнение к ответу Энни,
Assign
копирует из целевого списка (очистка содержимого исходного списка).
list1 := TList.Create();
for val:=1 to 3 do
list1.Add(Pointer(val)); // list1 contains {1,2,3}
list2 := TList.Create();
for val:=5 to 8 do
list2.Add(Pointer(val)); // list2 contains {5,6,7,8}
list2.Assign(list1); // list2 now contains {1,2,3}
list2.Assign(list1); // list2 still contains {1,2,3}
list2.Free();
list1.Free();
Я предполагаю, что оба списка являются общими TList<T>
, И что вы копируете существующие элементы, а не расширяете пункт назначения.
В этом случае, я думаю, for
цикл с присваиванием, используя :=
это путь Поскольку вы имеете дело с универсальным списком, вам нужно использовать оператор, который может работать с любым универсальным типом T
, Предполагая, что вам нужно поддержать T
это управляемый тип, тогда вы не можете выполнить простую копию памяти. Это оставляет вас с заданием.