TStringList的Find,IndexOf和Sort
procedure TForm1.Button1Click(Sender: TObject);
var
MyList: TStringList;
begin
MyList := TStringList.Create;
try
MyList.Add('');
MyList.Add('');
//经过测试可以知道,IndexOf是查询的是MyList中的每一项,而不单单是数据
ShowMessage(IntToStr(MyList.IndexOf('')));//结果为1
finally
MyList.Free;
end;
end;
来自:http://www.cnblogs.com/monkeyking/articles/234685.html
----------------------------------------------------------------------------
前几日工作很累,写代码时也有点心猿意马了,看到TStringList.Find便毫不犹豫地使用它在
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;
他用来取得指定行的字符串。分析也就此结束。
TStringList的Find,IndexOf和Sort的更多相关文章
- Delphi : TStringList的Find,IndexOf和Sort
关键:Find要事先Sort排序,Indexof不用排序. TStringList内部查找相关的数据.待调试代码时才知道痛苦,浪费无数时间后,只得一步步跟踪,才发 现Find方法返回的Index总是错 ...
- 删除delphi组件TStringlist中的重复项目
https://blog.csdn.net/ozhy111/article/details/87975663 删除delphi组件TStringlist中的重复项目 2019年02月27日 15:41 ...
- iOS - Swift Swift 语言新特性
1.Swift 2.0 带来哪些新变化 常规变化: 1.OS X 10.11.iOS 9 和 watchOS 2 SDK 采纳了一些 Objective-C 的特性用来提高 Swift 的编程体验, ...
- 总结swift 1.2适配swift2.0遇到的改变
swift1.2适配swift2.0 以下列举的是我在项目中遇到的需要修改的,基本常见的问题就没有罗列了. 1.find函数变成了为indexOf 2.sort变成了sortInPlace 3.sor ...
- JDK1.8 Lambda
1.模拟Model /** * Author:JsonLu * DateTime:16/12/8 14:01 * Email:jsonlu@qq.com * Desc: */ public class ...
- java 8 中lambda表达式学习
转自 http://blog.csdn.net/renfufei/article/details/24600507 http://www.jdon.com/idea/java/10-example-o ...
- Java Lambda表达式入门[转]
原文链接: Start Using Java Lambda Expressions http://blog.csdn.net/renfufei/article/details/24600507 下载示 ...
- Unity3D游戏GC优化总结---protobuf-net无GC版本优化实践
protobuf-net优化效果图 protobuf-net是Unity3D游戏开发中被广泛使用的Google Protocol Buffer库的c#版本,之所以c#版本被广泛使用,是因为c++版本的 ...
- C#之字符串
1 Replace string sayHello = "Hello World!"; Console.WriteLine(sayHello); sayHello = sayHel ...
随机推荐
- Linux基础学习-NFS网络文件系统实时文件共享
NFS网络文件系统 如果大家觉得Samba服务程序的配置太麻烦了,那么你共享文件的主机都是Linux系统,那么推荐大家在客户端部署nfs服务来共享文件.nfs(网络文件系统)服务可以将远程Linux系 ...
- Leetcode 145. 二叉树的后序遍历
题目链接 https://leetcode-cn.com/problems/binary-tree-postorder-traversal/description/ 题目描述 给定一个二叉树,返回它的 ...
- SQL_2_查询Select语句的使用
查询一词在SQL中并不是很恰当,在SQL中查询除了向数据库提出问题之外,还可以实现下面的功能: 1>建立或删除一个表 2>插入.修改.或删除一个行或列 3>用一个特定的命令从几个表中 ...
- BZOJ 3351: [ioi2009]Regions
对于一个询问(x,y)对y出现次数分类,若<=lim,在儿子处统计答案,若>lim则y的种类肯定<lim,在祖先处统计(仿佛要去重?但是没去重也过了,那个时限仿佛怎么做都能过) #i ...
- CodeForces 568B DP Symmetric and Transitive
题意: 根据离散数学的内容知道,一个二元关系是一个二元有序组<x, y>的集合. 然后有一些特殊的二元关系,比如等价关系,满足三个条件: 自反性,任意的x,都有二元关系<x, x&g ...
- Python虚拟机之异常控制流(四)
Python虚拟机中的异常控制流 先前,我们分别介绍了Python虚拟机之if控制流(一).Python虚拟机之for循环控制流(二)和Python虚拟机之while循环控制结构(三).这一章,我们来 ...
- python基础学习笔记——类的约束
⾸先, 你要清楚. 约束是对类的约束. 用一个例子说话: 公司让小明给他们的网站完善一个支付功能,小明写了两个类,如下: class QQpay: def pay(self,money): print ...
- MySQL数据库详解(一)执行SQL查询语句时,其底层到底经历了什么?
一条SQL查询语句是如何执行的? 前言 大家好,我是WZY,今天我们学习下MySQL的基础框架,看一件事千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题.同样,对于MyS ...
- day03 set集合,文件操作,字符编码以及函数式编程
嗯哼,第三天了 我们来get 下新技能,集合,个人认为集合就是用来list 比较的,就是把list 转换为set 然后做一些列表的比较啊求差值啊什么的. 先看怎么生成集合: list_s = [1,3 ...
- mysql update连表
UPDATE price_air_item t1 LEFT JOIN order_item t2 ON t1.ORDER_ITEM_ID = t2.ORDER_ITEM_ID SET t1.BUYER ...