不使用Sorted属性时高效删除TStrings重复项的性能最优方案
最优实现方案:哈希表辅助的线性遍历
针对你的需求(不依赖TStrings.Sorted、去重并保留原顺序、处理1.2MB IRC日志),基于哈希表的线性遍历是性能最优的实现方式,时间复杂度为O(n),远优于暴力对比的O(n²),完全适配你的数据规模。
核心逻辑
通过哈希表快速记录已出现过的日志行,遍历原列表时仅将未出现过的行加入结果列表,既能保证去重,又能严格保留原有顺序。哈希表的平均查找时间为O(1),整体遍历过程仅需一次线性扫描。
具体实现(Delphi环境)
方案1:使用TDictionary<string, Boolean>(兼容全Delphi版本)
function RemoveDuplicatesKeepOrder(const Source: TStrings): TArray<string>; var Seen: TDictionary<string, Boolean>; I: Integer; CurrentLine: string; ResultIndex: Integer; begin // 预分配结果数组容量,避免多次内存重分配 SetLength(Result, Source.Count); ResultIndex := 0; // 初始化哈希表,设置初始容量为原列表行数,减少扩容开销 Seen := TDictionary<string, Boolean>.Create(Source.Count); try for I := 0 to Source.Count - 1 do begin CurrentLine := Source.Strings[I]; if not Seen.ContainsKey(CurrentLine) then begin Seen.Add(CurrentLine, True); Result[ResultIndex] := CurrentLine; Inc(ResultIndex); end; end; // 截断结果数组至实际有效长度 SetLength(Result, ResultIndex); finally Seen.Free; end; end;
方案2:使用THashSet<string>(Delphi XE7+,更轻量)
THashSet是专门的集合类型,无需存储冗余值,内存开销略低于TDictionary:
function RemoveDuplicatesKeepOrder(const Source: TStrings): TArray<string>; var Seen: THashSet<string>; I: Integer; CurrentLine: string; ResultIndex: Integer; begin SetLength(Result, Source.Count); ResultIndex := 0; Seen := THashSet<string>.Create(Source.Count); try for I := 0 to Source.Count - 1 do begin CurrentLine := Source.Strings[I]; // Add方法返回True表示该行未在集合中存在 if Seen.Add(CurrentLine) then begin Result[ResultIndex] := CurrentLine; Inc(ResultIndex); end; end; SetLength(Result, ResultIndex); finally Seen.Free; end; end;
性能优化细节
- 预分配内存:结果数组初始容量设为原列表行数,避免动态扩容的内存拷贝开销;哈希表初始容量匹配原列表规模,减少哈希冲突和扩容次数。
- 避免冗余操作:直接引用原列表的字符串(Delphi字符串为引用计数类型,无需额外拷贝),减少内存消耗。
- 选择合适的哈希结构:
THashSet比TDictionary更适合纯集合场景,内存占用更低。
方案对比
- 暴力遍历法:每次新行都和已处理行逐一对比,时间复杂度O(n²),对于1.2MB日志(约1万-2万行)会产生百万级别的对比操作,性能极差,完全不推荐。
- 依赖
TStrings.Sorted:会打乱原有顺序,且不符合你的禁用要求,排除。
适配1.2MB日志的性能表现
该方案处理1万-2万行的IRC日志仅需毫秒级时间,内存开销仅为存储唯一行的引用+哈希表结构,完全在常规程序的内存承受范围内。
内容的提问来源于stack exchange,提问作者WayOfTheWright
相关产品推荐
相关产品推荐

