2014-01-13 16 views
6

我经常发现我需要'调整'一个TStringList来确切地保存N个元素,或者向列表中添加额外的空字符串,或者删除不需要的元素。更好的方式来调整TStringList的大小?

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

是否有一个更简单的方法来做到这一点,我忽略了?

+0

为什么不使用'TList '而不是? –

+0

我不记得不得不调整一个字符串列表来容纳N个元素,所以我想知道你的用例吗?也许其他数据结构可以更好地满足您的需求。 –

+0

为什么你需要调整列表的大小?这是一个重要的问题,因为它对最佳答案有重大影响。例如。调整大小是因为其他代码恰好需要N个元素与调整大小完全不同,以避免在您确切知道要保存多少个字符串时,为超大型列表创建冗余的内存开销。 –

回答

6

从执行TStringList.Assign来判断,没有更好的方法来做到这一点。他们基本上调用Clear并逐个添加字符串。

你当然应该把你的代码放到一个实用方法:

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

或者你可以使用一个类帮手,让你的方法似乎是TStringList本身的一部分。

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

TStringList.Capacity属性如何? –

+0

@VilleKrumlinde控制[容量](http://docwiki.embarcadero.com/Libraries/en/System.Classes.TStrings.Capacity)而不是计数。 –

+1

@DavidHeffernan是的,但在添加'循环之前添加'if Value> Count then Capacity = Value'可以提高性能。 – Roddy

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

不,容量不能这样工作。 – Roddy

+1

根据我的回答(http://stackoverflow.com/a/21091387/224704)设置容量有两个问题。 –

+0

我的坏@CraigYoung,错误的点击(标志) – nrathaus

2

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也很好,虽然我个人认为“班级帮手”功能是非常有用的。实施班级助手的“老办法”更加通用。

+0

我会说'不幸的缺点'是'计数'是不可写的。虽然他们是相关的,但是Capacity代表了Count的完全不同的概念。 – Roddy

+0

@Roddy True。在所有密切相关的“TList”允许“计数”可写入之后。真的没有任何理由让一个可写,而不是另一个。 –

+0

'TStringList.Grow'已经处理了性能问题 –

相关问题