Лучший способ изменить размер TStringList?
Я часто нахожу, что мне нужно "изменить размер" a TStringList
чтобы удерживать ровно N элементов, либо добавляя дополнительные пустые строки в список, либо удаляя ненужные.
на контейнере STL C++ я мог бы использовать resize
метод, но поскольку этого, похоже, не существует, я обычно делаю что-то вроде этого (предупреждение: псевдокод!).
list.beginUpdate;
while list.Count < requiredSize do
begin
list.add('');
end;
while list.Count > requiredSize do
begin
list.delete(list.count-1);
end;
list.endUpdate;
есть гораздо более простой способ сделать это, что я проглядел?
4 ответов
судя по реализации TStringList.Assign
, нет лучшего способа сделать это. Они в основном называют Clear
и добавьте строки один за другим.
вы, конечно, должны поместить свой код в метод утилиты:
procedure ResizeStringList(List : TStrings; ANewSize: Integer);
begin
...
end;
или вы можете использовать помощник класса, чтобы ваш метод казался частью .
метод в вашем вопросе-это лучшее, что вы можете сделать. Вы можете сделать его чище, если используете помощник класса. Например:
type
TStringsHelper = class helper for TStrings
procedure SetCount(Value: Integer);
end;
procedure TStringsHelper.SetCount(Value: Integer);
begin
BeginUpdate;
try
while Count<Value do
Add('');
while Count>Value do
Delete(Count-1);
finally
EndUpdate;
end;
end;
и тогда вы можете написать:
List.SetCount(requiredSize);
на Capacity
свойство почти идеально, потому что оно выделит правильное количество записей во внутреннем массиве. Тем не менее, у него есть печальные недостатки, которые:
- вновь выделенная память не инициализируется.
- количество элементов
Strings.Count
не обновляется.
поскольку архитектура компонента Delphi относится к базовому типу TStrings
, вы можете предоставить свой конкретный подкласс, который может поддерживать более эффективный изменение функциональности. Е. Г. рассмотрим следующую реализацию TList.SetCount
.
procedure TList.SetCount(NewCount: Integer);
var
I: Integer;
begin
if (NewCount < 0) or (NewCount > MaxListSize) then
Error(@SListCountError, NewCount);
if NewCount > FCapacity then
SetCapacity(NewCount);
if NewCount > FCount then
FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), 0)
else
for I := FCount - 1 downto NewCount do
Delete(I);
FCount := NewCount;
end;
после обновления емкости, если есть вновь выделенная память, она инициализируется с помощью FillChar
. Это намного эффективнее, чем добавление / удаление элементов по одному за раз.
таким образом, вы можете либо предоставить свою собственную независимую конкретную реализацию TStrings
подкласс, или просто сделайте копию Delphi's TStringList
который включает в себя соответствующий SetCount
метод.
тем не менее, я считаю маловероятным, что этот раздел кода будет испытывать какие-либо проблемы с производительностью, поэтому вашего собственного решения, завернутого в соответствующие методы утилиты, будет достаточно. Дэвид также хорошо, хотя лично я не считаю, что функция "помощник класса" настолько полезна. "Старый способ" реализации помощников классов гораздо более универсален.
var
List: TStringList;
Assert(requiredSize >= 0);
if requiredSize > List.Count then
List.Capacity := requiredSize
else
while List.Count > requiredSize do
List.Delete(List.Count - 1);