更好地调整TStringList的方法?

时间:2014-01-13 09:58:59

标签: delphi tstringlist

我经常发现我需要'调整'一个TStringList来调整N个元素,或者在列表中添加额外的空字符串,或者删除不必要的字符串。

在C ++ STL容器上,我可以使用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 个答案:

答案 0 :(得分:6)

TStringList.Assign的实施情况来看,没有更好的方法可以做到这一点。他们基本上会调用Clear并逐个添加字符串。

您当然应该将代码放入实用程序方法中:

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

或者您可以使用类帮助程序使您的方法看起来是TStringList本身的一部分。

答案 1 :(得分:3)

您问题中的方法是您可以做的最好的方法。如果使用类助手,可以使其更清晰。例如:

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);

答案 2 :(得分:3)

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的TStringList,其中包含适当的SetCount方法。

但是,我发现这部分代码不太可能遇到任何性能问题,因此用适当的实用方法包装的自己的解决方案就足够了。 David's answer也很好,但我个人并不认为“类助手”功能非常有用。实施班助手的“老方法”更加通用。

答案 3 :(得分:0)

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);