Delphi : TStringList的Find,IndexOf和Sort
关键:Find要事先Sort排序,Indexof不用排序。
TStringList内部查找相关的数据。待调试代码时才知道痛苦,浪费无数时间后,只得一步步跟踪,才发
现Find方法返回的Index总是错误的,当时一阵郁闷,随手按下F1键,Find的Help文档展现眼前,对于该
函数是这样描述的:
Locates the index for a string in a sorted list and indicates whether a string with that
value already exists in the list.
在Note部分又再次强调:
Only use Find with sorted lists. For unsorted lists, use the IndexOf method instead.
只怪自己一时懒惰,在不了解的情况下便抛弃习惯了的IndexOf,轻易使用新函数。但同时我也来了兴趣,为什么Find只能在使用TStringList.Sort方法后才能正常返回数据呢?
老办法,直接跳到Classes文件中查看源代码:
function TStringList.Find(const S: string; var Index: Integer): Boolean;
var
L, H, I, C: Integer;
begin
Result := False;
L := 0;
H := FCount - 1;
while L <= H do
begin
I := (L + H) shr 1;
C := CompareStrings(FList^[I].FString, S);
if C < 0 then L := I + 1
else begin
H := I - 1;
if C = 0 then
begin
Result := True;
if Duplicates <> dupAccept then L := I;
end;
end;
end;
Index := L;
end;
还是被吓了一跳,怎么感觉这么复杂,仔细一看才明白,原来是个折半查找算法。呵呵。
L,H变量分别代表Low和High,(L + H) shr 1就是求中间值的,完全等于(L + H) div 2,对于二进制,
右移一位就相当于整除2。其中CompareStrings是用来对比两个字符串大小的:
function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
if CaseSensitive then
Result := AnsiCompareStr(S1, S2)
else
Result := AnsiCompareText(S1, S2);
end;
这里的CaseSensitive用来标记是否大小写敏感,AnsiCompareStr是大小写敏感的,AnsiCompareText则
反之。另外在Help文档中还特地说明了两个函数进行判断时,小写字符是小于大写字符的,比如'a'<'A'
。请注意,这一点是与ASCII不相同的地方(如果再跟下去,你可以发现这两个函数是对API的一个封装,
而且封装了Linux和Windows的两个版本)。
此时我们返回到Find函数本身,又会发现在判断条件中只有C<0和C=0的情况,也就是说它只能搜索升序
排列的StringList。
忍不住,再看了看Sort方法。
procedure TStringList.Sort;
begin
CustomSort(StringListCompareStrings);
end;
简单的不能再简单,一行语句。CustomSort是一个公共方法,供用户使用自定义的比较规则进行排序。
StringListCompareStrings参数中放置的就是自定义比较规则的函数:
TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;
CustomSort的代码如下:
procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
if not Sorted and (FCount > 1) then
begin
Changing;
QuickSort(0, FCount - 1, Compare);
Changed;
end;
end;
Changing和Changed主要是用来触发FOnChanging和FOnChanged的,具体内容可以自己看代码。而
QuickSort则是使用快速排序算法和用户自定义的比较规则进行排序了,再跟入到QuickSort代码中:
procedure TStringList.QuickSort(L, R: Integer; SCompare: TStringListSortCompare);
var
I, J, P: Integer;
begin
repeat
I := L;
J := R;
P := (L + R) shr 1;
repeat
while SCompare(Self, I, P) < 0 do Inc(I);
while SCompare(Self, J, P) > 0 do Dec(J);
if I <= J then
begin
ExchangeItems(I, J);
if P = I then
P := J
else if P = J then
P := I;
Inc(I);
Dec(J);
end;
until I > J;
if L < J then QuickSort(L, J, SCompare);
L := I;
until I >= R;
end;
哈哈,正是这一段
while SCompare(Self, I, P) < 0 do Inc(I);
while SCompare(Self, J, P) > 0 do Dec(J);
使得TStringList是按照升序排列。至此,大致原因弄明白了。
再看看IndexOf是如何实现搜索的,刚开始我认为它肯定是使用For循环遍历每个Item,遇到相同的内容
则跳出循环,结果发现它确实也是这么做的,只是中间做了一些优化,假如StringList已经排序过,它
会自动使用效率更高的Find方法进行查找,另外它使用Result作为循环变量,对资源的利用极其充分。
代码如下:
function TStringList.IndexOf(const S: string): Integer;
begin
if not Sorted then Result := inherited IndexOf(S) else
if not Find(S, Result) then Result := -1;
end;
其中继承使用了父类TStrings中的IndexOf方法
function TStrings.IndexOf(const S: string): Integer;
begin
for Result := 0 to GetCount - 1 do
if CompareStrings(Get(Result), S) = 0 then Exit;
Result := -1;
end;
这段代码中的Get方法在TStrings中则是纯虚函数。
function Get(Index: Integer): string; virtual; abstract;
纯虚函数怎么能用,倒。那既然能用,只有一个可能,就是子类TStringList中实现了Get方法。返回到
TStringList中,在果然看到以下代码:
function TStringList.Get(Index: Integer): string;
begin
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Result := FList^[Index].FString;
end;
他用来取得指定行的字符串。分析也就此结束。
》》》》》》》》》》》》》》》》》》》》》》》》》》》》
Find是折半查找,速度应当是最快了,而indexof默认是 for 轮回所有item了。 但find应用前必须先排序 sort 不然返回 index错误。
示例如下:
var lst:TStringList ;
i:Integer ;
begin
lst:=TStringList.Create ;
try
lst:=TStringList.Create ;
lst.CaseSensitive :=true;
lst.Delimiter :="","";
lst.DelimitedText :=Edit1.Text ;
ShowMessage(IntToStr(lst.IndexOf(Edit2.Text) ));
lst.Sort ;
if lst.Find(Edit2.Text ,i) then
ShowMessage(IntToStr(i));
finally
lst.Free ;
end;
eidt2 内容 如下字符串 010a,010A,200a,200b,905a
Delphi : TStringList的Find,IndexOf和Sort的更多相关文章
- (转载)Delphi TStringList的用法
Delphi TStringList的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. TStringList 常用方法与属性: var List: TStringL ...
- Delphi TStringList的用法
Delphi TStringList的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. TStringList 常用方法与属性: var List: TStringL ...
- delphi TStringList 用法详解
转自: http://blog.163.com/you888@188/blog/static/67239619201472365642633/ delphi TStringList 用法详解 2014 ...
- TStringList的Find,IndexOf和Sort
procedure TForm1.Button1Click(Sender: TObject); var MyList: TStringList; begin MyList := TStringList ...
- Delphi TstringList Stringlist的特殊用法
procedure TForm1.btn1Click(Sender : TObject); var m : Integer; s : string; strlst ...
- 删除delphi组件TStringlist中的重复项目
https://blog.csdn.net/ozhy111/article/details/87975663 删除delphi组件TStringlist中的重复项目 2019年02月27日 15:41 ...
- 教程-TObjectList.Clear、TStringList.Clear方法对象有没有被释放
相关资料: http://www.cnblogs.com/rogge7/p/4631796.html delphiTStringList通过AddObject方法添加对象. object里存的只是指向 ...
- Delphi 快速读取TXT 指定行的数据
http://blog.csdn.net/MichaelJScofield/article/details/41869785 Delphi 快速读取TXT 指定行的数据 分类:Delphi个人挫品 ( ...
- iOS - Swift Swift 语言新特性
1.Swift 2.0 带来哪些新变化 常规变化: 1.OS X 10.11.iOS 9 和 watchOS 2 SDK 采纳了一些 Objective-C 的特性用来提高 Swift 的编程体验, ...
随机推荐
- Spring Boot 2.x实战之定时任务调度
在后端开发中,有些场景是需要使用定时任务的,例如:定时同步一批数据.定时清理一些数据,在Spring Boot中提供了@Scheduled注解就提供了定时调度的功能,对于简单的.单机的调度方案是足够了 ...
- Hdfs的HA高可用
1.Hdfs的HA高可用:保证Hdfs高可用,其实就是保证namenode的高可用,保证namenode的高可用的机制有两个,editlog共享机制+ZKFC.ZKFC就是ZookeeperFailO ...
- SSM整合Dubbo登陆案例
登陆案例 一.创建Service项目存放共同数据 1.1 创建实体类 private long id; private String loginName; private String userNa ...
- Python3.X下安装Scrapy
Python3.X下安装Scrapy (转载) 2017年08月09日 15:19:30 jingzhilie7908 阅读数:519 标签: python 相信很多同学对于爬虫需要安装Scrap ...
- java.security KeyPairGenerator
KeyPairGenerator 类用于生成公钥和私钥对.密钥对生成器是使用 getInstance 工厂方法(返回一个给定类的实例的静态方法)构造的. 特定算法的密钥对生成器可以创建能够与此算法一起 ...
- shell脚本编程之变量简介及脚本执行过程
脚本变量简介 变量类型:字符型.数值型.真.假:事先确定数据的存放格式和长度: 变量存放在内存空间: 编译型语言,没有额外的处理逻辑,属于强类型语言: 脚本型语言,可以有解释器控制:所以,可以是弱类型 ...
- 生活中需要一台mac本子
用了好多年的windows系统,各种快捷键玩得飞起.当时对mac笔记本的印象就是. mac本子好高大上,搞设计的人才会去用的.(这个也是我听其他人说的) 在当时公司搞IOS开发的人中,面对这个高大上的 ...
- weblogic介绍
快速阅读 介绍weblogic中间件,以及自身架构和几个基本概念,如何下载,安装等后面再详细介绍 . 什么是weblogic WebLogic最早由 WebLogic Inc. 开发,后并入BEA 公 ...
- NoSql数据库Redis系列(4)——Redis数据持久化(AOF)
上一篇文章我们介绍了Redis的RDB持久化,RDB 持久化存在一个缺点是一定时间内做一次备份,如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失).对于数据完整性要求很严 ...
- Linux crontab 定时任务使用
1.介绍 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程: 与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动crond进程 ...