Best way to resize a TStringList?

I often find that I need to โ€œresizeโ€ a TStringList to hold exactly N elements, adding extra blank lines to the list or deleting unnecessary ones.

In a C ++ STL container, I could use the resize method, but it doesn't seem to exist, I usually do something like this (warning: pseudo-code!).

 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; 

Is there an easier way to do this that I forgot about?

+6
source share
4 answers

Judging by the implementation of TStringList.Assign , there is no better way to do this. They are mostly called Clear and add lines one at a time.

Of course, you must enter your code in the utility method:

 procedure ResizeStringList(List : TStrings; ANewSize: Integer); begin ... end; 

Or you can use the class helper to make your method seem to be part of the TStringList itself.

+6
source

The method in your question is the best you can do. You can make it cleaner if you use the class helper. For instance:

 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; 

And then you can write:

 List.SetCount(requiredSize); 
+3
source

The Capacity property is almost perfect, because it will allocate the correct number of records in the internal array. However, it has unfortunate flaws that:

  • Recently allocated memory is not initialized.
  • The number of Strings.Count elements is not updated.

Since the architecture of the Delphi component is of the base type of TStrings , you can provide your own specific subclass that can support more efficient resizing functions. For instance. consider the following implementation of 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; 

After the Capacity upgrade, if there is a newly allocated memory, it is initialized using FillChar . This is much more efficient than adding / removing items one at a time.

So, you can either provide your own independent concrete implementation of the TStrings subclass, or simply make a copy of the Delphi TStringList , which includes the corresponding SetCount method.

However, this suggests that this section of the code is unlikely to have performance problems, so your own solution wrapped in the appropriate utilities will be sufficient. David's answer is also good, although I personally don't find the class helper feature useful. The "old way" to implement class helpers is much more universal.

+2
source
 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); 
0
source

All Articles